Index: src/sftp.c
===================================================================
RCS file: /cvsroot/libssh2/libssh2/src/sftp.c,v
retrieving revision 1.34
diff -u -r1.34 sftp.c
--- src/sftp.c 18 Apr 2007 18:51:04 -0000 1.34
+++ src/sftp.c 19 Apr 2007 16:44:21 -0000
@@ -84,6 +84,8 @@
LIBSSH2_SFTP_HANDLE *handles;
unsigned long last_errno;
+
+ time_t requirev_start;
};
#define LIBSSH2_SFTP_HANDLE_FILE 0
@@ -158,10 +160,15 @@
unsigned char buffer[4]; /* To store the packet length */
unsigned char *packet;
unsigned long packet_len, packet_received;
+ int rc;
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Waiting for packet: %s
block", should_block ? "will" : "willnot");
libssh2_channel_set_blocking(channel, should_block);
- if (4 != _libssh2_channel_read(channel, (char *)buffer, 4)) {
+ rc = _libssh2_channel_read(channel, (char *)buffer, 4);
+ if (!should_block && (rc == PACKET_EAGAIN)) {
+ return PACKET_EAGAIN;
+ }
+ else if (4 != rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
"Timeout waiting for FXP packet", 0);
return -1;
@@ -181,27 +188,34 @@
return -1;
}
- packet_received = 0;
- while (packet_len > packet_received) {
- long bytes_received =
- _libssh2_channel_read(channel,
- (char *)packet + packet_received,
- packet_len - packet_received);
-
- if (bytes_received < 0) {
- libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
"Receive error waiting for SFTP packet", 0);
- LIBSSH2_FREE(session, packet);
- return -1;
- }
- packet_received += bytes_received;
- }
+ packet_received = 0;
+ while (packet_len > packet_received) {
+ long bytes_received = _libssh2_channel_read(channel, (char
*)packet + packet_received, packet_len - packet_received);
+
+ if (!should_block && (bytes_received == PACKET_EAGAIN)) {
+#warning "XXX - This is not right, but adding a partial packet causes crashes"
+ bytes_received = 0;
+// if (libssh2_sftp_packet_add(sftp, packet,
packet_received)) {
+// LIBSSH2_FREE(session, packet);
+// return -1;
+// }
+// _libssh2_debug(session, LIBSSH2_DBG_SFTP,
"libssh2_sftp_packet_read(): read %ld bytes: EAGAIN", packet_received);
+// return PACKET_EAGAIN;
+ }
+ else if (bytes_received < 0) {
+ libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
"Receive error waiting for SFTP packet", 0);
+ LIBSSH2_FREE(session, packet);
+ return -1;
+ }
+ packet_received += bytes_received;
+ }
- if (libssh2_sftp_packet_add(sftp, packet, packet_len)) {
- LIBSSH2_FREE(session, packet);
- return -1;
- }
+ if (libssh2_sftp_packet_add(sftp, packet, packet_len)) {
+ LIBSSH2_FREE(session, packet);
+ return -1;
+ }
- return packet[0];
+ return packet[0];
}
/* }}} */
@@ -263,28 +277,32 @@
*/
static int libssh2_sftp_packet_require(LIBSSH2_SFTP *sftp, unsigned char
packet_type, unsigned long request_id, unsigned char **data, unsigned long
*data_len)
{
- LIBSSH2_SESSION *session = sftp->channel->session;
- _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) {
- /* A packet was available in the packet brigade */
- return 0;
- }
-
- while (session->socket_state == LIBSSH2_SOCKET_CONNECTED) {
- int ret = libssh2_sftp_packet_read(sftp, 1);
- if (ret <= 0) {
- return -1;
- }
-
- 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, data_len, 0);
- }
- }
-
- /* Only reached if the socket died */
- return -1;
+ LIBSSH2_SESSION *session = sftp->channel->session;
+ int bl = libssh2_channel_get_blocking(sftp->channel);
+ _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) {
+ /* The right packet was available in the packet brigade */
+ return 0;
+ }
+
+ while (session->socket_state == LIBSSH2_SOCKET_CONNECTED) {
+ int ret = libssh2_sftp_packet_read(sftp, bl);
+ if (!bl && (ret == PACKET_EAGAIN)) {
+ return PACKET_EAGAIN;
+ }
+ else if (ret <= 0) {
+ return -1;
+ }
+
+ 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, data_len, 0);
+ }
+ }
+
+ /* Only reached if the socket died */
+ return -1;
}
/* }}} */
@@ -298,40 +316,69 @@
unsigned char **data,
unsigned long *data_len)
{
- int i;
- time_t start = time(NULL);
-
- /* Flush */
- while (libssh2_sftp_packet_read(sftp, 0) > 0);
-
- while (sftp->channel->session->socket_state ==
LIBSSH2_SOCKET_CONNECTED) {
- int ret;
- for(i = 0; i < num_valid_responses; i++) {
- if (libssh2_sftp_packet_ask(sftp, valid_responses[i],
- request_id, data,
- data_len, 0) == 0) {
- return 0;
- }
- }
-
- ret = libssh2_sftp_packet_read(sftp, 1);
- if (ret < 0) {
- return -1;
- }
- if (ret == 0) {
- /* prevent busy-looping */
- long left = LIBSSH2_READ_TIMEOUT -
- (time(NULL) - start);
-
- if((left <= 0) ||
- (libssh2_waitsocket(sftp->channel->session,
- left)<=0)) {
- return PACKET_TIMEOUT;
- }
- }
- }
-
- return -1;
+ int i;
+ int bl = libssh2_channel_get_blocking(sftp->channel);
+
+ /*
+ * If no timeout is active, start a new one and flush
+ * any pending packets
+ */
+ if (sftp->requirev_start == 0) {
+ _libssh2_debug(sftp->channel->session, LIBSSH2_DBG_SFTP,
"_requirev(): Initialize timeout");
+ sftp->requirev_start = time(NULL);
+
+ /* Flush */
+ while (libssh2_sftp_packet_read(sftp, 0) > 0);
+ }
+
+ while (sftp->channel->session->socket_state ==
LIBSSH2_SOCKET_CONNECTED) {
+ int ret;
+
+ for(i = 0; i < num_valid_responses; i++) {
+ if (libssh2_sftp_packet_ask(sftp, valid_responses[i],
request_id,
+
data, data_len, 0) == 0) {
+ /*
+ * Set to zero before all returns to say
+ * the timeout is not active
+ */
+ _libssh2_debug(sftp->channel->session,
LIBSSH2_DBG_SFTP, "_requirev(): found in ask");
+ sftp->requirev_start = 0;
+ return 0;
+ }
+ }
+
+ ret = libssh2_sftp_packet_read(sftp, bl);
+ if (!bl && (ret == PACKET_EAGAIN)) {
+ _libssh2_debug(sftp->channel->session,
LIBSSH2_DBG_SFTP, "_requirev(): PACKET_EAGAIN");
+ return PACKET_EAGAIN;
+ }
+ else if (ret < 0) {
+ sftp->requirev_start = 0;
+ _libssh2_debug(sftp->channel->session,
LIBSSH2_DBG_SFTP, "_requirev(): -1");
+ return -1;
+ }
+ else if (ret == 0) {
+ /* prevent busy-looping */
+ if ((LIBSSH2_READ_TIMEOUT - (time(NULL) -
sftp->requirev_start)) <= 0) {
+ _libssh2_debug(sftp->channel->session,
LIBSSH2_DBG_SFTP, "_requirev(): PACKET_TIMEOUT");
+ return PACKET_TIMEOUT;
+ }
+ ret = libssh2_waitsocket(sftp->channel->session, 1);
+ if (!bl && (ret == PACKET_EAGAIN)) {
+ _libssh2_debug(sftp->channel->session,
LIBSSH2_DBG_SFTP, "_requirev(): PACKET_EAGAIN 2");
+ return PACKET_EAGAIN;
+ }
+ else if (ret <= 0) {
+ sftp->requirev_start = 0;
+ _libssh2_debug(sftp->channel->session,
LIBSSH2_DBG_SFTP, "_requirev(): PACKET_TIMEOUT 2");
+ return PACKET_TIMEOUT;
+ }
+ }
+ }
+
+ _libssh2_debug(sftp->channel->session, LIBSSH2_DBG_SFTP, "_requirev():
-1 2");
+ sftp->requirev_start = 0;
+ return -1;
}
/* }}} */
@@ -459,6 +506,7 @@
LIBSSH2_CHANNEL *channel;
unsigned char *data, *s, buffer[9]; /* sftp_header(5){excludes
request_id} + version_id(4) */
unsigned long data_len;
+ int rc;
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Initializing SFTP
subsystem");
channel = libssh2_channel_open_session(session);
@@ -500,8 +548,11 @@
return NULL;
}
- if (libssh2_sftp_packet_require(sftp, SSH_FXP_VERSION, 0,
- &data, &data_len)) {
+#warning "XXX - Looping on PACKET_EAGAIN (blocking) until fix is migrated up
farther"
+ while ((rc = libssh2_sftp_packet_require(sftp, SSH_FXP_VERSION,
0, &data, &data_len)) == PACKET_EAGAIN) {
+ ;
+ }
+ if (rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
"Timeout waiting for response from SFTP
subsystem", 0);
libssh2_channel_free(channel);
@@ -574,6 +625,7 @@
unsigned char *packet, *data, *s;
static const unsigned char fopen_responses[2] = { SSH_FXP_HANDLE,
SSH_FXP_STATUS };
unsigned long request_id;
+ int rc;
s = packet = LIBSSH2_ALLOC(session, packet_len);
if (!packet) {
@@ -603,7 +655,11 @@
}
LIBSSH2_FREE(session, packet);
- if (libssh2_sftp_packet_requirev(sftp, 2, fopen_responses, request_id,
&data, &data_len)) {
+#warning "XXX - Looping on PACKET_EAGAIN (blocking) until fix is migrated up
farther"
+ while ((rc = libssh2_sftp_packet_requirev(sftp, 2,
fopen_responses, request_id, &data, &data_len)) == PACKET_EAGAIN) {
+ ;
+ }
+ if (rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout
waiting for status message", 0);
return NULL;
}
@@ -670,6 +726,7 @@
size_t bytes_read = 0;
size_t bytes_requested = 0;
size_t total_read = 0;
+ int rc;
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Reading %lu bytes from SFTP
handle", (unsigned long)buffer_maxlen);
packet = LIBSSH2_ALLOC(session, packet_len);
@@ -717,8 +774,11 @@
return -1;
}
- if (libssh2_sftp_packet_requirev(sftp, 2, read_responses,
request_id,
- &data, &data_len)) {
+#warning "XXX - Looping on PACKET_EAGAIN (blocking) until fix is migrated up
farther"
+ while ((rc = libssh2_sftp_packet_requirev(sftp,
2, read_responses, request_id, &data, &data_len)) == PACKET_EAGAIN) {
+ ;
+ }
+ if (rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
"Timeout waiting for status message", 0);
return -1;
@@ -810,131 +870,203 @@
}
/* }}} */
-/* {{{ libssh2_sftp_readdir
- * Read from an SFTP directory handle
+/* {{{ _libssh2_sftp_readdir
+ * Read from an SFTP directory handle blocking/non-blocking depending on state
*/
-LIBSSH2_API int libssh2_sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char
*buffer, size_t buffer_maxlen, LIBSSH2_SFTP_ATTRIBUTES *attrs)
+static int _libssh2_sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char *buffer,
size_t buffer_maxlen, LIBSSH2_SFTP_ATTRIBUTES *attrs)
{
- LIBSSH2_SFTP *sftp = handle->sftp;
- LIBSSH2_CHANNEL *channel = sftp->channel;
- LIBSSH2_SESSION *session = channel->session;
- LIBSSH2_SFTP_ATTRIBUTES attrs_dummy;
- unsigned long data_len, request_id, filename_len, num_names;
- ssize_t packet_len = handle->handle_len + 13; /* packet_len(4) +
packet_type(1) + request_id(4) + handle_len(4) */
- unsigned char *packet, *s, *data;
- static const unsigned char read_responses[2] = { SSH_FXP_NAME,
SSH_FXP_STATUS };
-
- if (handle->u.dir.names_left) {
- /* A prior request returned more than one directory entry,
feed it back from the buffer */
- unsigned char *s = (unsigned char *)handle->u.dir.next_name;
- unsigned long real_filename_len = libssh2_ntohu32(s);
-
- filename_len = real_filename_len; s += 4;
- if (filename_len > buffer_maxlen) {
- filename_len = buffer_maxlen;
- }
- memcpy(buffer, s, filename_len); s +=
real_filename_len;
-
- /* The filename is not null terminated, make it so if possible
*/
- if (filename_len < buffer_maxlen) {
- buffer[filename_len] = '\0';
- }
-
- /* Skip longname */
- s += 4 + libssh2_ntohu32(s);
+ LIBSSH2_SFTP *sftp = handle->sftp;
+ LIBSSH2_CHANNEL *channel = sftp->channel;
+ LIBSSH2_SESSION *session = channel->session;
+ LIBSSH2_SFTP_ATTRIBUTES attrs_dummy;
+ unsigned long data_len, request_id, filename_len, num_names;
+ ssize_t packet_len = handle->handle_len + 13; /* packet_len(4) +
packet_type(1) + request_id(4) + handle_len(4) */
+ unsigned char *packet, *s, *data;
+ unsigned char read_responses[2] = { SSH_FXP_NAME, SSH_FXP_STATUS };
+ int rc;
+
+ if (handle->u.dir.names_left) {
+ /* A prior request returned more than one directory entry, feed
it back from the buffer */
+ unsigned char *s = (unsigned char *)handle->u.dir.next_name;
+ unsigned long real_filename_len = libssh2_ntohu32(s);
+
+ filename_len = real_filename_len;
+ s += 4;
+ if (filename_len > buffer_maxlen) {
+ filename_len = buffer_maxlen;
+ }
+ memcpy(buffer, s, filename_len);
+ s += real_filename_len;
+
+ /* The filename is not null terminated, make it so if possible
*/
+ if (filename_len < buffer_maxlen) {
+ buffer[filename_len] = '\0';
+ }
+
+ /* Skip longname */
+ s += 4 + libssh2_ntohu32(s);
+
+ if (attrs) {
+ memset(attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES));
+ }
+ s += libssh2_sftp_bin2attr(attrs ? attrs : &attrs_dummy, s);
+
+ handle->u.dir.next_name = (char *)s;
+ if ((--handle->u.dir.names_left) == 0) {
+ LIBSSH2_FREE(session, handle->u.dir.names_packet);
+ }
- if (attrs) {
- memset(attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES));
- }
- s += libssh2_sftp_bin2attr(attrs ? attrs : &attrs_dummy, s);
-
- handle->u.dir.next_name = (char *)s;
- if ((--handle->u.dir.names_left) == 0) {
- LIBSSH2_FREE(session, handle->u.dir.names_packet);
- }
-
- return filename_len;
- }
-
- /* Request another entry(entries?) */
+ return filename_len;
+ }
- s = packet = LIBSSH2_ALLOC(session, packet_len);
- if (!packet) {
- libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to
allocate memory for FXP_READDIR packet", 0);
- return -1;
- }
+ /* Request another entry(entries?) */
- libssh2_htonu32(s, packet_len - 4);
s += 4;
- *(s++) = SSH_FXP_READDIR;
- request_id = sftp->request_id++;
- libssh2_htonu32(s, request_id);
s += 4;
- libssh2_htonu32(s, handle->handle_len); s += 4;
- memcpy(s, handle->handle, handle->handle_len); s +=
handle->handle_len;
+ s = packet = LIBSSH2_ALLOC(session, packet_len);
+ if (!packet) {
+ libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate
memory for FXP_READDIR packet", 0);
+ return -1;
+ }
- _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Reading entries from
directory handle");
- if (packet_len != libssh2_channel_write(channel, (char *)packet,
- packet_len)) {
- libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to
send FXP_READ command", 0);
- LIBSSH2_FREE(session, packet);
- return -1;
- }
- LIBSSH2_FREE(session, packet);
+ libssh2_htonu32(s, packet_len - 4);
+ s += 4;
+ *(s++) = SSH_FXP_READDIR;
+ request_id = sftp->request_id++;
+ libssh2_htonu32(s, request_id);
+ s += 4;
+ libssh2_htonu32(s, handle->handle_len);
+ s += 4;
+ memcpy(s, handle->handle, handle->handle_len);
+ s += handle->handle_len;
+
+ _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Reading entries from
directory handle");
+ if (libssh2_channel_get_blocking(channel)) {
+ if (packet_len != libssh2_channel_write(channel, (char
*)packet, packet_len)) {
+ libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
"Unable to send FXP_READ command", 0);
+ LIBSSH2_FREE(session, packet);
+ return -1;
+ }
+ } else {
+ if ((rc = libssh2_channel_writenb(channel, (char *)packet,
packet_len)) == PACKET_EAGAIN) {
+ LIBSSH2_FREE(session, packet);
+ return rc;
+ }
+ if (packet_len != rc) {
+ libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
"Unable to send FXP_READ command", 0);
+ LIBSSH2_FREE(session, packet);
+ return -1;
+ }
+ }
+ LIBSSH2_FREE(session, packet);
- if (libssh2_sftp_packet_requirev(sftp, 2, read_responses, request_id,
&data, &data_len)) {
- libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout
waiting for status message", 0);
- return -1;
- }
+#warning "XXX - Looping on PACKET_EAGAIN (blocking) until fix is migrated up
farther"
+ while ((rc = libssh2_sftp_packet_requirev(sftp, 2, read_responses,
request_id, &data, &data_len)) == PACKET_EAGAIN) {
+ ;
+ }
+ if (rc) {
+ libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout
waiting for status message", 0);
+ return -1;
+ }
- if (data[0] == SSH_FXP_STATUS) {
- int retcode;
+ if (data[0] == SSH_FXP_STATUS) {
+ int retcode;
- retcode = libssh2_ntohu32(data + 5);
- LIBSSH2_FREE(session, data);
- if (retcode == LIBSSH2_FX_EOF) {
- return 0;
- } else {
- sftp->last_errno = retcode;
- libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
"SFTP Protocol Error", 0);
- return -1;
- }
- }
+ retcode = libssh2_ntohu32(data + 5);
+ LIBSSH2_FREE(session, data);
+ if (retcode == LIBSSH2_FX_EOF) {
+ return 0;
+ } else {
+ sftp->last_errno = retcode;
+ libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
"SFTP Protocol Error", 0);
+ return -1;
+ }
+ }
- num_names = libssh2_ntohu32(data + 5);
- _libssh2_debug(session, LIBSSH2_DBG_SFTP, "%lu entries returned",
num_names);
- if (num_names <= 0) {
- LIBSSH2_FREE(session, data);
- return (num_names == 0) ? 0 : -1;
- }
+ num_names = libssh2_ntohu32(data + 5);
+ _libssh2_debug(session, LIBSSH2_DBG_SFTP, "%lu entries returned",
num_names);
+ if (num_names <= 0) {
+ LIBSSH2_FREE(session, data);
+ return (num_names == 0) ? 0 : -1;
+ }
- if (num_names == 1) {
- unsigned long real_filename_len = libssh2_ntohu32(data + 9);
+ if (num_names == 1) {
+ unsigned long real_filename_len = libssh2_ntohu32(data + 9);
- filename_len = real_filename_len;
- if (filename_len > buffer_maxlen) {
- filename_len = buffer_maxlen;
- }
- memcpy(buffer, data + 13, filename_len);
+ filename_len = real_filename_len;
+ if (filename_len > buffer_maxlen) {
+ filename_len = buffer_maxlen;
+ }
+ memcpy(buffer, data + 13, filename_len);
+
+ /* The filename is not null terminated, make it so if possible
*/
+ if (filename_len < buffer_maxlen) {
+ buffer[filename_len] = '\0';
+ }
+
+ if (attrs) {
+ memset(attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES));
+ libssh2_sftp_bin2attr(attrs, data + 13 +
real_filename_len + (4 + libssh2_ntohu32(data + 13 + real_filename_len)));
+ }
+ LIBSSH2_FREE(session, data);
- /* The filename is not null terminated, make it so if possible
*/
- if (filename_len < buffer_maxlen) {
- buffer[filename_len] = '\0';
- }
+ return filename_len;
+ }
- if (attrs) {
- memset(attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES));
- libssh2_sftp_bin2attr(attrs, data + 13 +
real_filename_len + (4 + libssh2_ntohu32(data + 13 + real_filename_len)));
- }
- LIBSSH2_FREE(session, data);
+ handle->u.dir.names_left = num_names;
+ handle->u.dir.names_packet = data;
+ handle->u.dir.next_name = (char *)data + 9;
- return filename_len;
- }
+ /* Be lazy, just use the name popping mechanism from the start of the
function */
+ return libssh2_sftp_readdir(handle, buffer, buffer_maxlen, attrs);
+}
+/* }}} */
- handle->u.dir.names_left = num_names;
- handle->u.dir.names_packet = data;
- handle->u.dir.next_name = (char *)data + 9;
+/* {{{ libssh2_sftp_readdir
+ * Read from an SFTP directory handle blocking
+ */
+LIBSSH2_API int libssh2_sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char
*buffer,
+ size_t
buffer_maxlen, LIBSSH2_SFTP_ATTRIBUTES *attrs)
+{
+ int rc;
+ LIBSSH2_CHANNEL *ch = handle->sftp->channel;
+ int bl = libssh2_channel_get_blocking(ch);
+
+ /* set blocking */
+ libssh2_channel_set_blocking(ch, 1);
+
+ rc = _libssh2_sftp_readdir(handle, buffer, buffer_maxlen, attrs);
+
+ /* restore state */
+ libssh2_channel_set_blocking(ch, bl);
+
+ if(rc < 0) {
+ /* precent accidental returning of other return codes since
+ this API does not support/provide those */
+ return -1;
+ }
+
+ return rc;
+}
+/* }}} */
- /* Be lazy, just use the name popping mechanism from the start of the
function */
- return libssh2_sftp_readdir(handle, buffer, buffer_maxlen, attrs);
+/* {{{ libssh2_sftp_readdirnb
+ * Read from an SFTP directory handle non-blocking
+ */
+LIBSSH2_API int libssh2_sftp_readdirnb(LIBSSH2_SFTP_HANDLE *handle, char
*buffer,
+
size_t buffer_maxlen, LIBSSH2_SFTP_ATTRIBUTES *attrs)
+{
+ int rc;
+ LIBSSH2_CHANNEL *ch = handle->sftp->channel;
+ int bl = libssh2_channel_get_blocking(ch);
+
+ /* set non-blocking */
+ libssh2_channel_set_blocking(ch, 0);
+
+ rc = _libssh2_sftp_readdir(handle, buffer, buffer_maxlen, attrs);
+
+ /* restore state */
+ libssh2_channel_set_blocking(ch, bl);
+
+ return rc;
}
/* }}} */
@@ -942,56 +1074,80 @@
* Write data to a file handle
*/
static ssize_t _libssh2_sftp_write(LIBSSH2_SFTP_HANDLE *handle,
- const char *buffer,
- size_t count)
+ const char
*buffer,
+ size_t count)
{
- LIBSSH2_SFTP *sftp = handle->sftp;
- LIBSSH2_CHANNEL *channel = sftp->channel;
- LIBSSH2_SESSION *session = channel->session;
- unsigned long data_len, request_id, retcode;
- ssize_t packet_len = handle->handle_len + count + 25; /* packet_len(4)
+ packet_type(1) + request_id(4) + handle_len(4) + offset(8) + count(4) */
- unsigned char *packet, *s, *data;
-
- _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Writing %lu bytes",
(unsigned long)count);
- s = packet = LIBSSH2_ALLOC(session, packet_len);
- if (!packet) {
- libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to
allocate memory for FXP_WRITE packet", 0);
- return -1;
- }
-
- libssh2_htonu32(s, packet_len - 4);
s += 4;
- *(s++) = SSH_FXP_WRITE;
- request_id = sftp->request_id++;
- libssh2_htonu32(s, request_id);
s += 4;
- libssh2_htonu32(s, handle->handle_len); s += 4;
- memcpy(s, handle->handle, handle->handle_len); s +=
handle->handle_len;
- libssh2_htonu64(s, handle->u.file.offset); s += 8;
- libssh2_htonu32(s, count);
s += 4;
- memcpy(s, buffer, count);
s += count;
-
- if (packet_len != libssh2_channel_write(channel, (char *)packet,
packet_len)) {
- libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to
send FXP_WRITE command", 0);
- LIBSSH2_FREE(session, packet);
- return -1;
- }
- LIBSSH2_FREE(session, packet);
-
- if (libssh2_sftp_packet_require(sftp, SSH_FXP_STATUS, request_id,
&data, &data_len)) {
- libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout
waiting for status message", 0);
- return -1;
- }
-
- retcode = libssh2_ntohu32(data + 5);
- LIBSSH2_FREE(session, data);
-
- if (retcode == LIBSSH2_FX_OK) {
- handle->u.file.offset += count;
- return count;
- }
- libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "SFTP Protocol
Error", 0);
- sftp->last_errno = retcode;
-
- return -1;
+ LIBSSH2_SFTP *sftp = handle->sftp;
+ LIBSSH2_CHANNEL *channel = sftp->channel;
+ LIBSSH2_SESSION *session = channel->session;
+ unsigned long data_len, request_id, retcode;
+ ssize_t packet_len = handle->handle_len + count + 25; /* packet_len(4)
+ packet_type(1) + request_id(4) + handle_len(4) + offset(8) + count(4) */
+ unsigned char *packet, *s, *data;
+ int rc;
+
+ _libssh2_debug(session, LIBSSH2_DBG_SFTP, "Writing %lu bytes",
(unsigned long)count);
+ s = packet = LIBSSH2_ALLOC(session, packet_len);
+ if (!packet) {
+ libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate
memory for FXP_WRITE packet", 0);
+ return -1;
+ }
+
+ libssh2_htonu32(s, packet_len - 4);
s += 4;
+ *(s++) = SSH_FXP_WRITE;
+ request_id = sftp->request_id++;
+ libssh2_htonu32(s, request_id);
s += 4;
+ libssh2_htonu32(s, handle->handle_len); s += 4;
+ memcpy(s, handle->handle, handle->handle_len); s +=
handle->handle_len;
+ libssh2_htonu64(s, handle->u.file.offset); s += 8;
+ libssh2_htonu32(s, count);
s += 4;
+ memcpy(s, buffer, count);
s += count;
+
+ if (libssh2_channel_get_blocking(channel)) {
+ if (packet_len != libssh2_channel_write(channel, (char
*)packet, packet_len)) {
+ libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
"Unable to send FXP_READ command", 0);
+ LIBSSH2_FREE(session, packet);
+ return -1;
+ }
+ } else {
+ if ((rc = libssh2_channel_writenb(channel, (char *)packet,
packet_len)) == PACKET_EAGAIN) {
+ LIBSSH2_FREE(session, packet);
+ return rc;
+ }
+ if (packet_len != rc) {
+ libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
"Unable to send FXP_READ command", 0);
+ LIBSSH2_FREE(session, packet);
+ return -1;
+ }
+ }
+ LIBSSH2_FREE(session, packet);
+
+ if (libssh2_channel_get_blocking(channel)) {
+ if (libssh2_sftp_packet_require(sftp, SSH_FXP_STATUS,
request_id, &data, &data_len)) {
+ libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
"Timeout waiting for status message", 0);
+ return -1;
+ }
+ } else {
+#warning "XXX - Looping on PACKET_EAGAIN (blocking) until fix is migrated up
farther"
+ while ((rc = libssh2_sftp_packet_require(sftp, SSH_FXP_STATUS,
request_id, &data, &data_len)) == PACKET_EAGAIN) {
+ ;
+ }
+ if (packet_len != rc) {
+ libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT,
"Timeout waiting for status message", 0);
+ return -1;
+ }
+ }
+
+ retcode = libssh2_ntohu32(data + 5);
+ LIBSSH2_FREE(session, data);
+
+ if (retcode == LIBSSH2_FX_OK) {
+ handle->u.file.offset += count;
+ return count;
+ }
+ libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "SFTP Protocol
Error", 0);
+ sftp->last_errno = retcode;
+
+ return -1;
}
/* }}} */
@@ -1052,6 +1208,7 @@
/* packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) */
unsigned char *packet, *s, *data;
static const unsigned char fstat_responses[2] = { SSH_FXP_ATTRS,
SSH_FXP_STATUS };
+ int rc;
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Issuing %s command",
setstat ? "set-stat" : "stat");
s = packet = LIBSSH2_ALLOC(session, packet_len);
@@ -1077,7 +1234,11 @@
}
LIBSSH2_FREE(session, packet);
- if (libssh2_sftp_packet_requirev(sftp, 2, fstat_responses, request_id,
&data, &data_len)) {
+#warning "XXX - Looping on PACKET_EAGAIN (blocking) until fix is migrated up
farther"
+ while ((rc = libssh2_sftp_packet_requirev(sftp, 2,
fstat_responses, request_id, &data, &data_len)) == PACKET_EAGAIN) {
+ ;
+ }
+ if (rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout
waiting for status message", 0);
return -1;
}
@@ -1133,6 +1294,7 @@
unsigned long data_len, retcode, request_id;
ssize_t packet_len = handle->handle_len + 13; /* packet_len(4) +
packet_type(1) + request_id(4) + handle_len(4) */
unsigned char *packet, *s, *data;
+ int rc;
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Closing handle");
s = packet = LIBSSH2_ALLOC(session, packet_len);
@@ -1155,7 +1317,11 @@
}
LIBSSH2_FREE(session, packet);
- if (libssh2_sftp_packet_require(sftp, SSH_FXP_STATUS, request_id,
&data, &data_len)) {
+#warning "XXX - Looping on PACKET_EAGAIN (blocking) until fix is migrated up
farther"
+ while ((rc = libssh2_sftp_packet_require(sftp, SSH_FXP_STATUS,
request_id, &data, &data_len)) == PACKET_EAGAIN) {
+ ;
+ }
+ if (rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout
waiting for status message", 0);
return -1;
}
@@ -1202,6 +1368,7 @@
unsigned long data_len, retcode, request_id;
ssize_t packet_len = filename_len + 13; /* packet_len(4) +
packet_type(1) + request_id(4) + filename_len(4) */
unsigned char *packet, *s, *data;
+ int rc;
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Unlinking %s", filename);
s = packet = LIBSSH2_ALLOC(session, packet_len);
@@ -1225,7 +1392,11 @@
}
LIBSSH2_FREE(session, packet);
- if (libssh2_sftp_packet_require(sftp, SSH_FXP_STATUS, request_id,
&data, &data_len)) {
+#warning "XXX - Looping on PACKET_EAGAIN (blocking) until fix is migrated up
farther"
+ while ((rc = libssh2_sftp_packet_require(sftp, SSH_FXP_STATUS,
request_id, &data, &data_len)) == PACKET_EAGAIN) {
+ ;
+ }
+ if (rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout
waiting for status message", 0);
return -1;
}
@@ -1257,6 +1428,7 @@
/*
packet_len(4) + packet_type(1) + request_id(4) +
source_filename_len(4) + dest_filename_len(4) + flags(4){SFTP5+) */
unsigned char *packet, *s, *data;
+ int rc;
if (sftp->version < 2) {
libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, "Server
does not support RENAME", 0);
@@ -1291,7 +1463,11 @@
}
LIBSSH2_FREE(session, packet);
- if (libssh2_sftp_packet_require(sftp, SSH_FXP_STATUS, request_id,
&data, &data_len)) {
+#warning "XXX - Looping on PACKET_EAGAIN (blocking) until fix is migrated up
farther"
+ while ((rc = libssh2_sftp_packet_require(sftp, SSH_FXP_STATUS,
request_id, &data, &data_len)) == PACKET_EAGAIN) {
+ ;
+ }
+ if (rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout
waiting for status message", 0);
return -1;
}
@@ -1337,6 +1513,7 @@
ssize_t packet_len = path_len + 13 + libssh2_sftp_attrsize(&attrs);
/* packet_len(4) + packet_type(1) + request_id(4) +
path_len(4) */
unsigned char *packet, *s, *data;
+ int rc;
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Creating directory %s with
mode 0%lo", path, mode);
s = packet = LIBSSH2_ALLOC(session, packet_len);
@@ -1363,7 +1540,11 @@
}
LIBSSH2_FREE(session, packet);
- if (libssh2_sftp_packet_require(sftp, SSH_FXP_STATUS, request_id,
&data, &data_len)) {
+#warning "XXX - Looping on PACKET_EAGAIN (blocking) until fix is migrated up
farther"
+ while ((rc = libssh2_sftp_packet_require(sftp, SSH_FXP_STATUS,
request_id, &data, &data_len)) == PACKET_EAGAIN) {
+ ;
+ }
+ if (rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout
waiting for status message", 0);
return -1;
}
@@ -1391,6 +1572,7 @@
unsigned long data_len, retcode, request_id;
ssize_t packet_len = path_len + 13; /* packet_len(4) + packet_type(1)
+ request_id(4) + path_len(4) */
unsigned char *packet, *s, *data;
+ int rc;
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "Removing directory: %s",
path);
s = packet = LIBSSH2_ALLOC(session, packet_len);
@@ -1413,7 +1595,11 @@
}
LIBSSH2_FREE(session, packet);
- if (libssh2_sftp_packet_require(sftp, SSH_FXP_STATUS, request_id,
&data, &data_len)) {
+#warning "XXX - Looping on PACKET_EAGAIN (blocking) until fix is migrated up
farther"
+ while ((rc = libssh2_sftp_packet_require(sftp, SSH_FXP_STATUS,
request_id, &data, &data_len)) == PACKET_EAGAIN) {
+ ;
+ }
+ if (rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout
waiting for status message", 0);
return -1;
}
@@ -1443,6 +1629,7 @@
/*
packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */
unsigned char *packet, *s, *data;
static const unsigned char stat_responses[2] = { SSH_FXP_ATTRS,
SSH_FXP_STATUS };
+ int rc;
_libssh2_debug(session, LIBSSH2_DBG_SFTP, "%s %s", (stat_type ==
LIBSSH2_SFTP_SETSTAT) ? "Set-statting" : (stat_type == LIBSSH2_SFTP_LSTAT ?
"LStatting" : "Statting"), path);
s = packet = LIBSSH2_ALLOC(session, packet_len);
@@ -1479,7 +1666,11 @@
}
LIBSSH2_FREE(session, packet);
- if (libssh2_sftp_packet_requirev(sftp, 2, stat_responses, request_id,
&data, &data_len)) {
+#warning "XXX - Looping on PACKET_EAGAIN (blocking) until fix is migrated up
farther"
+ while ((rc = libssh2_sftp_packet_requirev(sftp, 2,
stat_responses, request_id, &data, &data_len)) == PACKET_EAGAIN) {
+ ;
+ }
+ if (rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout
waiting for status message", 0);
return -1;
}
@@ -1518,6 +1709,7 @@
/*
packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */
unsigned char *packet, *s, *data;
static const unsigned char link_responses[2] = { SSH_FXP_NAME,
SSH_FXP_STATUS };
+ int rc;
if ((sftp->version < 3) &&
(link_type != LIBSSH2_SFTP_REALPATH)) {
@@ -1562,7 +1754,11 @@
}
LIBSSH2_FREE(session, packet);
- if (libssh2_sftp_packet_requirev(sftp, 2, link_responses, request_id,
&data, &data_len)) {
+#warning "XXX - Looping on PACKET_EAGAIN (blocking) until fix is migrated up
farther"
+ while ((rc = libssh2_sftp_packet_requirev(sftp, 2,
link_responses, request_id, &data, &data_len)) == PACKET_EAGAIN) {
+ ;
+ }
+ if (rc) {
libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout
waiting for status message", 0);
return -1;
}
@@ -1607,3 +1803,22 @@
return sftp->last_errno;
}
/* }}} */
+
+/* {{{ libssh2_sftp_set_blocking
+ * Set a channel's blocking mode on or off, this is an accessor
+ * to the channel through the SFTP session handle
+ */
+LIBSSH2_API void libssh2_sftp_set_blocking(LIBSSH2_SFTP *session, int
blocking) {
+ libssh2_channel_set_blocking(session->channel, blocking);
+}
+/* }}} */
+
+/* {{{ libssh2_sftp_get_blocking
+ * Returns a channel's blocking mode on or off, this is an accessor
+ * to the channel through the SFTP session handle
+ */
+LIBSSH2_API int libssh2_sftp_get_blocking(LIBSSH2_SFTP *session) {
+ return libssh2_channel_get_blocking(session->channel);
+}
+/* }}} */
+
-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
libssh2-devel mailing list
libssh2-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/libssh2-devel