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

Reply via email to