]> granicus.if.org Git - curl/commitdiff
Fix to work with the latest CVS version of libssh2
authorJames Housley <jim@thehousleys.net>
Fri, 8 Jun 2007 16:02:57 +0000 (16:02 +0000)
committerJames Housley <jim@thehousleys.net>
Fri, 8 Jun 2007 16:02:57 +0000 (16:02 +0000)
* As of (LIBSSH2_APINO >= 200706012030) there are not *nb() functions
* As of (LIBSSH2_APINO >= 200706012030) most libssh2_*() functions
  can return LIBSSH2_ERROR_EAGAIN to indicate that the call would block.

To make the code work as previously, blocking, all the code has been
updated so that when (LIBSSH2_APINO >= 200706012030) it loops simulating
blocking.  This allows the existing code to function and not hold up
the upcoming release.

lib/ssh.c

index 5bba639863ace553cd43c69e100a2cd01d10488c..184a74b6943f15203ef2186a63bb27fc8f73caea 100644 (file)
--- a/lib/ssh.c
+++ b/lib/ssh.c
@@ -310,13 +310,27 @@ CURLcode Curl_ssh_connect(struct connectdata *conn, bool *done)
     Curl_safefree(working_path);
     return CURLE_FAILED_INIT;
   }
+  
+#if (LIBSSH2_APINO >= 200706012030)
+  /* Set libssh2 to non-blocking, since cURL is all non-blocking */
+  libssh2_session_set_blocking(ssh->ssh_session, 0);
+#endif /* LIBSSH2_APINO >= 200706012030 */
 
 #ifdef CURL_LIBSSH2_DEBUG
-  libssh2_trace(ssh->ssh_session, LIBSSH2_TRACE_CONN|LIBSSH2_TRACE_TRANS|LIBSSH2_TRACE_KEX|LIBSSH2_TRACE_AUTH|LIBSSH2_TRACE_SCP|LIBSSH2_TRACE_SFTP|LIBSSH2_TRACE_ERROR|LIBSSH2_TRACE_PUBLICKEY);
+  libssh2_trace(ssh->ssh_session, LIBSSH2_TRACE_CONN|LIBSSH2_TRACE_TRANS|
+                LIBSSH2_TRACE_KEX|LIBSSH2_TRACE_AUTH|LIBSSH2_TRACE_SCP|
+                LIBSSH2_TRACE_SFTP|LIBSSH2_TRACE_ERROR|
+                LIBSSH2_TRACE_PUBLICKEY);
   infof(data, "SSH socket: %d\n", sock);
 #endif /* CURL_LIBSSH2_DEBUG */
 
-  if (libssh2_session_startup(ssh->ssh_session, sock)) {
+#if (LIBSSH2_APINO >= 200706012030)
+  while ((i = libssh2_session_startup(ssh->ssh_session, sock)) ==
+         LIBSSH2_ERROR_EAGAIN);
+#else /* !(LIBSSH2_APINO >= 200706012030) */
+  i = libssh2_session_startup(ssh->ssh_session, sock);
+#endif /* !(LIBSSH2_APINO >= 200706012030) */
+  if (i) {
     failf(data, "Failure establishing ssh session");
     libssh2_session_free(ssh->ssh_session);
     ssh->ssh_session = NULL;
@@ -353,6 +367,20 @@ CURLcode Curl_ssh_connect(struct connectdata *conn, bool *done)
    * presumably with a blank username. That won't work in my experience.
    * So always specify it here.
    */
+#if (LIBSSH2_APINO >= 200706012030)
+  do {
+    authlist = libssh2_userauth_list(ssh->ssh_session, ssh->user,
+                                     strlen(ssh->user));
+      
+    if (!authlist && (libssh2_session_last_errno(ssh->ssh_session) !=
+                      LIBSSH2_ERROR_EAGAIN)) {
+      libssh2_session_free(ssh->ssh_session);
+      ssh->ssh_session = NULL;
+      Curl_safefree(working_path);
+      return CURLE_OUT_OF_MEMORY;
+    }
+  } while (!authlist);
+#else /* !(LIBSSH2_APINO >= 200706012030) */
   authlist = libssh2_userauth_list(ssh->ssh_session, ssh->user,
                                    strlen(ssh->user));
   if (!authlist) {
@@ -361,6 +389,7 @@ CURLcode Curl_ssh_connect(struct connectdata *conn, bool *done)
     Curl_safefree(working_path);
     return CURLE_OUT_OF_MEMORY;
   }
+#endif /* !(LIBSSH2_APINO >= 200706012030) */
   infof(data, "SSH authentication methods available: %s\n", authlist);
 
   /*
@@ -402,8 +431,16 @@ CURLcode Curl_ssh_connect(struct connectdata *conn, bool *done)
     if (rsa_pub[0]) {
       /* The function below checks if the files exists, no need to stat() here.
       */
-      if (libssh2_userauth_publickey_fromfile(ssh->ssh_session, ssh->user,
-                                              rsa_pub, rsa, passphrase) == 0) {
+#if (LIBSSH2_APINO >= 200706012030)
+      while ((i = libssh2_userauth_publickey_fromfile(ssh->ssh_session,
+                                                      ssh->user, rsa_pub,
+                                                      rsa, passphrase)) ==
+             LIBSSH2_ERROR_EAGAIN);
+#else /* !(LIBSSH2_APINO >= 200706012030) */
+      i = libssh2_userauth_publickey_fromfile(ssh->ssh_session, ssh->user,
+                                          rsa_pub, rsa, passphrase);
+#endif /* !(LIBSSH2_APINO >= 200706012030) */
+      if (i == 0) {
         authed = TRUE;
         infof(conn->data, "Initialized SSH public key authentication\n");
       }
@@ -412,7 +449,14 @@ CURLcode Curl_ssh_connect(struct connectdata *conn, bool *done)
   if (!authed &&
       (data->set.ssh_auth_types & CURLSSH_AUTH_PASSWORD) &&
       (strstr(authlist, "password") != NULL)) {
-    if (!libssh2_userauth_password(ssh->ssh_session, ssh->user, ssh->passwd)) {
+#if (LIBSSH2_APINO >= 200706012030)
+    while ((i = libssh2_userauth_password(ssh->ssh_session, ssh->user,
+                                          ssh->passwd)) ==
+           LIBSSH2_ERROR_EAGAIN);
+#else /* !(LIBSSH2_APINO >= 200706012030) */
+    i = libssh2_userauth_password(ssh->ssh_session, ssh->user, ssh->passwd);
+#endif /* !(LIBSSH2_APINO >= 200706012030) */
+    if (i == 0) {
       authed = TRUE;
       infof(conn->data, "Initialized password authentication\n");
     }
@@ -423,9 +467,18 @@ CURLcode Curl_ssh_connect(struct connectdata *conn, bool *done)
   if (!authed && (data->set.ssh_auth_types & CURLSSH_AUTH_KEYBOARD)
       && (strstr(authlist, "keyboard-interactive") != NULL)) {
     /* Authentication failed. Continue with keyboard-interactive now. */
-    if (libssh2_userauth_keyboard_interactive_ex(ssh->ssh_session, ssh->user,
+#if (LIBSSH2_APINO >= 200706012030)
+    while ((i = libssh2_userauth_keyboard_interactive_ex(ssh->ssh_session,
+                                                         ssh->user,
+                                                         strlen(ssh->user),
+                                                         &kbd_callback)) ==
+           LIBSSH2_ERROR_EAGAIN);
+#else /* !(LIBSSH2_APINO >= 200706012030) */
+    i = libssh2_userauth_keyboard_interactive_ex(ssh->ssh_session, ssh->user,
                                                  strlen(ssh->user),
-                                                 &kbd_callback) == 0) {
+                                                 &kbd_callback);
+#endif /* !(LIBSSH2_APINO >= 200706012030) */
+    if (i == 0) {
       authed = TRUE;
       infof(conn->data, "Initialized keyboard interactive authentication\n");
     }
@@ -453,6 +506,19 @@ CURLcode Curl_ssh_connect(struct connectdata *conn, bool *done)
     /*
      * Start the libssh2 sftp session
      */
+#if (LIBSSH2_APINO >= 200706012030)
+    do {
+      ssh->sftp_session = libssh2_sftp_init(ssh->ssh_session);
+      if (!ssh->sftp_session && (libssh2_session_last_errno(ssh->ssh_session) !=
+                                 LIBSSH2_ERROR_EAGAIN)) {
+        failf(data, "Failure initialising sftp session\n");
+        libssh2_session_free(ssh->ssh_session);
+        ssh->ssh_session = NULL;
+        Curl_safefree(working_path);
+        return CURLE_FAILED_INIT;
+      }
+    } while (!ssh->sftp_session);
+#else /* !(LIBSSH2_APINO >= 200706012030) */
     ssh->sftp_session = libssh2_sftp_init(ssh->ssh_session);
     if (ssh->sftp_session == NULL) {
       failf(data, "Failure initialising sftp session\n");
@@ -461,11 +527,18 @@ CURLcode Curl_ssh_connect(struct connectdata *conn, bool *done)
       Curl_safefree(working_path);
       return CURLE_FAILED_INIT;
     }
+#endif /* !(LIBSSH2_APINO >= 200706012030) */
 
     /*
      * Get the "home" directory
      */
+#if (LIBSSH2_APINO >= 200706012030)
+    while ((i = libssh2_sftp_realpath(ssh->sftp_session, ".",
+                                      tempHome, PATH_MAX-1)) ==
+           LIBSSH2_ERROR_EAGAIN);
+#else /* !(LIBSSH2_APINO >= 200706012030) */
     i = libssh2_sftp_realpath(ssh->sftp_session, ".", tempHome, PATH_MAX-1);
+#endif /* !(LIBSSH2_APINO >= 200706012030) */
     if (i > 0) {
       /* It seems that this string is not always NULL terminated */
       tempHome[i] = '\0';
@@ -572,6 +645,21 @@ CURLcode Curl_scp_do(struct connectdata *conn, bool *done)
      * the destination file will be named the same name as the last directory
      * in the path.
      */
+#if (LIBSSH2_APINO >= 200706012030)
+    do {
+      scp->ssh_channel = libssh2_scp_send_ex(scp->ssh_session, scp->path,
+                                             LIBSSH2_SFTP_S_IRUSR|
+                                             LIBSSH2_SFTP_S_IWUSR|
+                                             LIBSSH2_SFTP_S_IRGRP|
+                                             LIBSSH2_SFTP_S_IROTH,
+                                             conn->data->set.infilesize, 0, 0);
+      if (!scp->ssh_channel &&
+          (libssh2_session_last_errno(scp->ssh_session) !=
+           LIBSSH2_ERROR_EAGAIN)) {
+        return CURLE_FAILED_INIT;
+      }
+    } while (!scp->ssh_channel);
+#else /* !(LIBSSH2_APINO >= 200706012030) */
     scp->ssh_channel = libssh2_scp_send_ex(scp->ssh_session, scp->path,
                                            LIBSSH2_SFTP_S_IRUSR|
                                            LIBSSH2_SFTP_S_IWUSR|
@@ -580,6 +668,7 @@ CURLcode Curl_scp_do(struct connectdata *conn, bool *done)
                                            conn->data->set.infilesize, 0, 0);
     if (!scp->ssh_channel)
       return CURLE_FAILED_INIT;
+#endif /* !(LIBSSH2_APINO >= 200706012030) */
 
     /* upload data */
     res = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, FIRSTSOCKET, NULL);
@@ -591,6 +680,22 @@ CURLcode Curl_scp_do(struct connectdata *conn, bool *done)
      */
     curl_off_t bytecount;
     memset(&sb, 0, sizeof(struct stat));
+#if (LIBSSH2_APINO >= 200706012030)
+    do {
+      scp->ssh_channel = libssh2_scp_recv(scp->ssh_session, scp->path, &sb);
+      if (!scp->ssh_channel &&
+          (libssh2_session_last_errno(scp->ssh_session) !=
+           LIBSSH2_ERROR_EAGAIN)) {
+        if ((sb.st_mode == 0) && (sb.st_atime == 0) && (sb.st_mtime == 0) &&
+            (sb.st_size == 0)) {
+          /* Since sb is still empty, it is likely the file was not found */
+          return CURLE_REMOTE_FILE_NOT_FOUND;
+        }
+        return libssh2_session_error_to_CURLE(
+          libssh2_session_last_error(scp->ssh_session, NULL, NULL, 0));
+      }
+    } while (!scp->ssh_channel);
+#else /* !(LIBSSH2_APINO >= 200706012030) */
     scp->ssh_channel = libssh2_scp_recv(scp->ssh_session, scp->path, &sb);
     if (!scp->ssh_channel) {
       if ((sb.st_mode == 0) && (sb.st_atime == 0) && (sb.st_mtime == 0) &&
@@ -601,6 +706,7 @@ CURLcode Curl_scp_do(struct connectdata *conn, bool *done)
       return libssh2_session_error_to_CURLE(
         libssh2_session_last_error(scp->ssh_session, NULL, NULL, 0));
     }
+#endif /* !(LIBSSH2_APINO >= 200706012030) */
     /* download data */
     bytecount = (curl_off_t) sb.st_size;
     conn->data->reqdata.maxdownload =  (curl_off_t) sb.st_size;
@@ -614,6 +720,7 @@ CURLcode Curl_scp_do(struct connectdata *conn, bool *done)
 CURLcode Curl_scp_done(struct connectdata *conn, CURLcode status,
                        bool premature)
 {
+  int rc;
   struct SSHPROTO *scp = conn->data->reqdata.proto.ssh;
   (void)premature; /* not used */
 
@@ -621,6 +728,25 @@ CURLcode Curl_scp_done(struct connectdata *conn, CURLcode status,
   scp->path = NULL;
 
   if (scp->ssh_channel) {
+#if (LIBSSH2_APINO >= 200706012030)
+    if (conn->data->set.upload) {
+      while ((rc = libssh2_channel_send_eof(scp->ssh_channel)) ==
+             LIBSSH2_ERROR_EAGAIN);
+      if (rc) {
+        infof(conn->data, "Failed to send libssh2 channel EOF\n");
+      }
+      while ((rc = libssh2_channel_wait_eof(scp->ssh_channel)) ==
+             LIBSSH2_ERROR_EAGAIN);
+      if (rc) {
+        infof(conn->data, "Failed to get channel EOF\n");
+      }
+      while ((rc = libssh2_channel_wait_closed(scp->ssh_channel)) ==
+             LIBSSH2_ERROR_EAGAIN);
+      if (rc) {
+        infof(conn->data, "Channel failed to close\n");
+      }
+    }
+#else /* !(LIBSSH2_APINO >= 200706012030) */
     if (conn->data->set.upload &&
         libssh2_channel_send_eof(scp->ssh_channel) < 0) {
       infof(conn->data, "Failed to send libssh2 channel EOF\n");
@@ -628,10 +754,16 @@ CURLcode Curl_scp_done(struct connectdata *conn, CURLcode status,
     if (libssh2_channel_close(scp->ssh_channel) < 0) {
       infof(conn->data, "Failed to stop libssh2 channel subsystem\n");
     }
+#endif /* !(LIBSSH2_APINO >= 200706012030) */
   }
 
   if (scp->ssh_session) {
+#if (LIBSSH2_APINO >= 200706012030)
+    while (libssh2_session_disconnect(scp->ssh_session, "Shutdown") == 
+           LIBSSH2_ERROR_EAGAIN);
+#else /* !(LIBSSH2_APINO >= 200706012030) */
     libssh2_session_disconnect(scp->ssh_session, "Shutdown");
+#endif /* !(LIBSSH2_APINO >= 200706012030) */
     libssh2_session_free(scp->ssh_session);
     scp->ssh_session = NULL;
   }
@@ -656,7 +788,7 @@ ssize_t Curl_scp_send(struct connectdata *conn, int sockindex,
    * NOTE: we should not store nor rely on connection-related data to be
    * in the SessionHandle struct
    */
-#ifdef LIBSSH2CHANNEL_EAGAIN
+#if defined(LIBSSH2CHANNEL_EAGAIN) && (LIBSSH2_APINO < 200706012030)
   nwrite = (ssize_t)
     libssh2_channel_writenb(conn->data->reqdata.proto.ssh->ssh_channel,
                             mem, len);
@@ -685,7 +817,7 @@ ssize_t Curl_scp_recv(struct connectdata *conn, int sockindex,
    * in the SessionHandle struct
    */
 
-#ifdef LIBSSH2CHANNEL_EAGAIN
+#if defined(LIBSSH2CHANNEL_EAGAIN) && (LIBSSH2_APINO < 200706012030)
   /* we prefer the non-blocking API but that didn't exist previously */
   nread = (ssize_t)
     libssh2_channel_readnb(conn->data->reqdata.proto.ssh->ssh_channel,
@@ -711,6 +843,7 @@ CURLcode Curl_sftp_do(struct connectdata *conn, bool *done)
   curl_off_t bytecount = 0;
   char *buf = data->state.buffer;
   unsigned long err = 0;
+  int rc;
 
   *done = TRUE; /* unconditionally */
 
@@ -729,6 +862,23 @@ CURLcode Curl_sftp_do(struct connectdata *conn, bool *done)
      *          If this is not done the destination file will be named the
      *          same name as the last directory in the path.
      */
+#if (LIBSSH2_APINO >= 200706012030)
+    do {
+      sftp->sftp_handle =
+        libssh2_sftp_open(sftp->sftp_session, sftp->path,
+                        LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC,
+                        LIBSSH2_SFTP_S_IRUSR|LIBSSH2_SFTP_S_IWUSR|
+                        LIBSSH2_SFTP_S_IRGRP|LIBSSH2_SFTP_S_IROTH);
+      if (!sftp->sftp_handle &&
+          (libssh2_session_last_errno(sftp->ssh_session) !=
+           LIBSSH2_ERROR_EAGAIN)) {
+        err = libssh2_sftp_last_error(sftp->sftp_session);
+        failf(conn->data, "Could not open remote file for writing: %s",
+              sftp_libssh2_strerror(err));
+        return sftp_libssh2_error_to_CURLE(err);
+      }
+    } while (!sftp->sftp_handle);
+#else /* !(LIBSSH2_APINO >= 200706012030) */
     sftp->sftp_handle =
       libssh2_sftp_open(sftp->sftp_session, sftp->path,
                         LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC,
@@ -740,6 +890,7 @@ CURLcode Curl_sftp_do(struct connectdata *conn, bool *done)
             sftp_libssh2_strerror(err));
       return sftp_libssh2_error_to_CURLE(err);
     }
+#endif /* !(LIBSSH2_APINO >= 200706012030) */
 
     /* upload data */
     res = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, FIRSTSOCKET, NULL);
@@ -758,6 +909,20 @@ CURLcode Curl_sftp_do(struct connectdata *conn, bool *done)
       int len, totalLen, currLen;
       char *line;
 
+#if (LIBSSH2_APINO >= 200706012030)
+      do {
+        sftp->sftp_handle =
+          libssh2_sftp_opendir(sftp->sftp_session, sftp->path);
+        if (!sftp->sftp_handle &&
+            (libssh2_session_last_errno(sftp->ssh_session) !=
+             LIBSSH2_ERROR_EAGAIN)) {
+          err = libssh2_sftp_last_error(sftp->sftp_session);
+          failf(conn->data, "Could not open directory for reading: %s",
+                sftp_libssh2_strerror(err));
+          return sftp_libssh2_error_to_CURLE(err);
+        }
+      } while (!sftp->sftp_handle);
+#else /* !(LIBSSH2_APINO >= 200706012030) */
       sftp->sftp_handle =
         libssh2_sftp_opendir(sftp->sftp_session, sftp->path);
       if (!sftp->sftp_handle) {
@@ -766,129 +931,148 @@ CURLcode Curl_sftp_do(struct connectdata *conn, bool *done)
             sftp_libssh2_strerror(err));
         return sftp_libssh2_error_to_CURLE(err);
       }
-
-      while ((len = libssh2_sftp_readdir(sftp->sftp_handle, filename,
-                                         PATH_MAX, &attrs)) > 0) {
-        filename[len] = '\0';
-
-        if (data->set.ftp_list_only) {
-          if ((attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) &&
-              ((attrs.permissions & LIBSSH2_SFTP_S_IFMT) ==
-               LIBSSH2_SFTP_S_IFDIR)) {
-            infof(data, "%s\n", filename);
+#endif /* !(LIBSSH2_APINO >= 200706012030) */
+
+      do {
+#if (LIBSSH2_APINO >= 200706012030)
+        while ((len = libssh2_sftp_readdir(sftp->sftp_handle, filename,
+                                           PATH_MAX, &attrs)) ==
+               LIBSSH2_ERROR_EAGAIN);
+#else /* !(LIBSSH2_APINO >= 200706012030) */
+        len = libssh2_sftp_readdir(sftp->sftp_handle, filename,
+                                   PATH_MAX, &attrs);
+#endif /* !(LIBSSH2_APINO >= 200706012030) */
+        if (len > 0) {
+          filename[len] = '\0';
+
+          if (data->set.ftp_list_only) {
+            if ((attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) &&
+                ((attrs.permissions & LIBSSH2_SFTP_S_IFMT) ==
+                 LIBSSH2_SFTP_S_IFDIR)) {
+              infof(data, "%s\n", filename);
+            }
           }
-        }
-        else {
-          totalLen = 80 + len;
-          line = (char *)malloc(totalLen);
-          if (!line)
-            return CURLE_OUT_OF_MEMORY;
-
-          if (!(attrs.flags & LIBSSH2_SFTP_ATTR_UIDGID))
-            attrs.uid = attrs.gid =0;
-
-          currLen = snprintf(line, totalLen, "----------   1 %5d %5d",
-                             attrs.uid, attrs.gid);
+          else {
+            totalLen = 80 + len;
+            line = (char *)malloc(totalLen);
+            if (!line)
+              return CURLE_OUT_OF_MEMORY;
 
-          if (attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) {
-            if ((attrs.permissions & LIBSSH2_SFTP_S_IFMT) ==
-                LIBSSH2_SFTP_S_IFDIR) {
-              line[0] = 'd';
-            }
-            else if ((attrs.permissions & LIBSSH2_SFTP_S_IFMT) ==
-                     LIBSSH2_SFTP_S_IFLNK) {
-              line[0] = 'l';
-            }
-            else if ((attrs.permissions & LIBSSH2_SFTP_S_IFMT) ==
-                     LIBSSH2_SFTP_S_IFSOCK) {
-              line[0] = 's';
-            }
-            else if ((attrs.permissions & LIBSSH2_SFTP_S_IFMT) ==
-                     LIBSSH2_SFTP_S_IFCHR) {
-              line[0] = 'c';
-            }
-            else if ((attrs.permissions & LIBSSH2_SFTP_S_IFMT) ==
-                     LIBSSH2_SFTP_S_IFBLK) {
-              line[0] = 'b';
-            }
-            if (attrs.permissions & LIBSSH2_SFTP_S_IRUSR) {
-              line[1] = 'r';
-            }
-            if (attrs.permissions & LIBSSH2_SFTP_S_IWUSR) {
-              line[2] = 'w';
-            }
-            if (attrs.permissions & LIBSSH2_SFTP_S_IXUSR) {
-              line[3] = 'x';
-            }
-            if (attrs.permissions & LIBSSH2_SFTP_S_IRGRP) {
-              line[4] = 'r';
-            }
-            if (attrs.permissions & LIBSSH2_SFTP_S_IWGRP) {
-              line[5] = 'w';
+            if (!(attrs.flags & LIBSSH2_SFTP_ATTR_UIDGID))
+              attrs.uid = attrs.gid =0;
+
+            currLen = snprintf(line, totalLen, "----------   1 %5d %5d",
+                               attrs.uid, attrs.gid);
+
+            if (attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) {
+              if ((attrs.permissions & LIBSSH2_SFTP_S_IFMT) ==
+                  LIBSSH2_SFTP_S_IFDIR) {
+                line[0] = 'd';
+              }
+              else if ((attrs.permissions & LIBSSH2_SFTP_S_IFMT) ==
+                       LIBSSH2_SFTP_S_IFLNK) {
+                line[0] = 'l';
+              }
+              else if ((attrs.permissions & LIBSSH2_SFTP_S_IFMT) ==
+                       LIBSSH2_SFTP_S_IFSOCK) {
+                line[0] = 's';
+              }
+              else if ((attrs.permissions & LIBSSH2_SFTP_S_IFMT) ==
+                       LIBSSH2_SFTP_S_IFCHR) {
+                line[0] = 'c';
+              }
+              else if ((attrs.permissions & LIBSSH2_SFTP_S_IFMT) ==
+                       LIBSSH2_SFTP_S_IFBLK) {
+                line[0] = 'b';
+              }
+              if (attrs.permissions & LIBSSH2_SFTP_S_IRUSR) {
+                line[1] = 'r';
+              }
+              if (attrs.permissions & LIBSSH2_SFTP_S_IWUSR) {
+                line[2] = 'w';
+              }
+              if (attrs.permissions & LIBSSH2_SFTP_S_IXUSR) {
+                line[3] = 'x';
+              }
+              if (attrs.permissions & LIBSSH2_SFTP_S_IRGRP) {
+                line[4] = 'r';
+              }
+              if (attrs.permissions & LIBSSH2_SFTP_S_IWGRP) {
+                line[5] = 'w';
+              }
+              if (attrs.permissions & LIBSSH2_SFTP_S_IXGRP) {
+                line[6] = 'x';
+              }
+              if (attrs.permissions & LIBSSH2_SFTP_S_IROTH) {
+                line[7] = 'r';
+              }
+              if (attrs.permissions & LIBSSH2_SFTP_S_IWOTH) {
+                line[8] = 'w';
+              }
+              if (attrs.permissions & LIBSSH2_SFTP_S_IXOTH) {
+                line[9] = 'x';
+              }
             }
-            if (attrs.permissions & LIBSSH2_SFTP_S_IXGRP) {
-              line[6] = 'x';
+            if (attrs.flags & LIBSSH2_SFTP_ATTR_SIZE) {
+              currLen += snprintf(line+currLen, totalLen-currLen, "%11lld",
+                                  attrs.filesize);
             }
-            if (attrs.permissions & LIBSSH2_SFTP_S_IROTH) {
-              line[7] = 'r';
+            if (attrs.flags & LIBSSH2_SFTP_ATTR_ACMODTIME) {
+              static const char * const months[12] = {
+                "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+                "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+              struct tm *nowParts;
+              time_t now, remoteTime;
+
+              now = time(NULL);
+              remoteTime = (time_t)attrs.mtime;
+              nowParts = localtime(&remoteTime);
+
+              if ((time_t)attrs.mtime > (now - (3600 * 24 * 180))) {
+                currLen += snprintf(line+currLen, totalLen-currLen,
+                                    " %s %2d %2d:%02d",
+                                    months[nowParts->tm_mon],
+                                    nowParts->tm_mday, nowParts->tm_hour,
+                                    nowParts->tm_min);
+              }
+              else {
+                currLen += snprintf(line+currLen, totalLen-currLen,
+                                    " %s %2d %5d", months[nowParts->tm_mon],
+                                    nowParts->tm_mday, 1900+nowParts->tm_year);
+              }
             }
-            if (attrs.permissions & LIBSSH2_SFTP_S_IWOTH) {
-              line[8] = 'w';
-            }
-            if (attrs.permissions & LIBSSH2_SFTP_S_IXOTH) {
-              line[9] = 'x';
-            }
-          }
-          if (attrs.flags & LIBSSH2_SFTP_ATTR_SIZE) {
-            currLen += snprintf(line+currLen, totalLen-currLen, "%11lld",
-                                attrs.filesize);
-          }
-          if (attrs.flags & LIBSSH2_SFTP_ATTR_ACMODTIME) {
-            static const char * const months[12] = {
-              "Jan", "Feb", "Mar", "Apr", "May", "Jun",
-              "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
-            struct tm *nowParts;
-            time_t now, remoteTime;
-
-            now = time(NULL);
-            remoteTime = (time_t)attrs.mtime;
-            nowParts = localtime(&remoteTime);
-
-            if ((time_t)attrs.mtime > (now - (3600 * 24 * 180))) {
-              currLen += snprintf(line+currLen, totalLen-currLen,
-                                  " %s %2d %2d:%02d", months[nowParts->tm_mon],
-                                  nowParts->tm_mday, nowParts->tm_hour,
-                                  nowParts->tm_min);
-            }
-            else {
-              currLen += snprintf(line+currLen, totalLen-currLen,
-                                  " %s %2d %5d", months[nowParts->tm_mon],
-                                  nowParts->tm_mday, 1900+nowParts->tm_year);
+            currLen += snprintf(line+currLen, totalLen-currLen, " %s",
+                                filename);
+            if ((attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) &&
+                ((attrs.permissions & LIBSSH2_SFTP_S_IFMT) ==
+                 LIBSSH2_SFTP_S_IFLNK)) {
+              char linkPath[PATH_MAX + 1];
+
+              snprintf(linkPath, PATH_MAX, "%s%s", sftp->path, filename);
+              len = libssh2_sftp_readlink(sftp->sftp_session, linkPath,
+                                          filename, PATH_MAX);
+              line = realloc(line, totalLen + 4 + len);
+              if (!line)
+                return CURLE_OUT_OF_MEMORY;
+
+              currLen += snprintf(line+currLen, totalLen-currLen, " -> %s",
+                                  filename);
             }
-          }
-          currLen += snprintf(line+currLen, totalLen-currLen, " %s", filename);
-          if ((attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) &&
-              ((attrs.permissions & LIBSSH2_SFTP_S_IFMT) ==
-               LIBSSH2_SFTP_S_IFLNK)) {
-            char linkPath[PATH_MAX + 1];
-
-            snprintf(linkPath, PATH_MAX, "%s%s", sftp->path, filename);
-            len = libssh2_sftp_readlink(sftp->sftp_session, linkPath, filename,
-                                        PATH_MAX);
-            line = realloc(line, totalLen + 4 + len);
-            if (!line)
-              return CURLE_OUT_OF_MEMORY;
 
-            currLen += snprintf(line+currLen, totalLen-currLen, " -> %s",
-                                filename);
+            currLen += snprintf(line+currLen, totalLen-currLen, "\n");
+            res = Curl_client_write(conn, CLIENTWRITE_BODY, line, 0);
+            free(line);
           }
-
-          currLen += snprintf(line+currLen, totalLen-currLen, "\n");
-          res = Curl_client_write(conn, CLIENTWRITE_BODY, line, 0);
-          free(line);
         }
-      }
+        else if (len <= 0) {
+          break;
+        }
+      } while (1);
+#if (LIBSSH2_APINO >= 200706012030)
+      while (libssh2_sftp_closedir(sftp->sftp_handle) == LIBSSH2_ERROR_EAGAIN);
+#else /* !(LIBSSH2_APINO >= 200706012030) */
       libssh2_sftp_closedir(sftp->sftp_handle);
+#endif /* !(LIBSSH2_APINO >= 200706012030) */
       sftp->sftp_handle = NULL;
 
       /* no data to transfer */
@@ -898,6 +1082,22 @@ CURLcode Curl_sftp_do(struct connectdata *conn, bool *done)
       /*
        * Work on getting the specified file
        */
+#if (LIBSSH2_APINO >= 200706012030)
+      do {
+        sftp->sftp_handle =
+          libssh2_sftp_open(sftp->sftp_session, sftp->path, LIBSSH2_FXF_READ,
+                          LIBSSH2_SFTP_S_IRUSR|LIBSSH2_SFTP_S_IWUSR|
+                          LIBSSH2_SFTP_S_IRGRP|LIBSSH2_SFTP_S_IROTH);
+        if (!sftp->sftp_handle &&
+            (libssh2_session_last_errno(sftp->ssh_session) !=
+                                   LIBSSH2_ERROR_EAGAIN)) {
+          err = libssh2_sftp_last_error(sftp->sftp_session);
+          failf(conn->data, "Could not open remote file for reading: %s",
+                sftp_libssh2_strerror(err));
+          return sftp_libssh2_error_to_CURLE(err);
+        }
+      } while (!sftp->sftp_handle);
+#else /* !(LIBSSH2_APINO >= 200706012030) */
       sftp->sftp_handle =
         libssh2_sftp_open(sftp->sftp_session, sftp->path, LIBSSH2_FXF_READ,
                           LIBSSH2_SFTP_S_IRUSR|LIBSSH2_SFTP_S_IWUSR|
@@ -908,8 +1108,15 @@ CURLcode Curl_sftp_do(struct connectdata *conn, bool *done)
             sftp_libssh2_strerror(err));
         return sftp_libssh2_error_to_CURLE(err);
       }
-
-      if (libssh2_sftp_stat(sftp->sftp_session, sftp->path, &attrs)) {
+#endif /* !(LIBSSH2_APINO >= 200706012030) */
+
+#if (LIBSSH2_APINO >= 200706012030)
+      while ((rc = libssh2_sftp_stat(sftp->sftp_session, sftp->path, &attrs))
+             == LIBSSH2_ERROR_EAGAIN);
+#else /* !(LIBSSH2_APINO >= 200706012030) */
+      rc = libssh2_sftp_stat(sftp->sftp_session, sftp->path, &attrs);
+#endif /* !(LIBSSH2_APINO >= 200706012030) */
+      if (rc) {
         /*
          * libssh2_sftp_open() didn't return an error, so maybe the server
          * just doesn't support stat()
@@ -935,19 +1142,31 @@ CURLcode Curl_sftp_do(struct connectdata *conn, bool *done)
                                 bytecount, FALSE, NULL, -1, NULL);
 #endif
       while (res == CURLE_OK) {
+#if (LIBSSH2_APINO >= 200706012030)
+        ssize_t nread;
+        
+        while ((nread = libssh2_sftp_read(data->reqdata.proto.ssh->sftp_handle,
+                                  buf, BUFSIZE-1)) == LIBSSH2_ERROR_EAGAIN);
+#else /* !(LIBSSH2_APINO >= 200706012030) */
         size_t nread;
         /* NOTE: most *read() functions return ssize_t but this returns size_t
-           which normally is unsigned! */
+          which normally is unsigned! */
         nread = libssh2_sftp_read(data->reqdata.proto.ssh->sftp_handle,
                                   buf, BUFSIZE-1);
+#endif /* !(LIBSSH2_APINO >= 200706012030) */
 
         if (nread > 0)
           buf[nread] = 0;
 
+#if (LIBSSH2_APINO >= 200706012030)
+        if (nread <= 0)
+          break;
+#else /* !(LIBSSH2_APINO >= 200706012030) */
         /* this check can be changed to a <= 0 when nread is changed to a
-           signed variable type */
+          signed variable type */
         if ((nread == 0) || (nread == (size_t)~0))
           break;
+#endif /* !(LIBSSH2_APINO >= 200706012030) */
 
         bytecount += nread;
 
@@ -980,6 +1199,7 @@ CURLcode Curl_sftp_done(struct connectdata *conn, CURLcode status,
 {
   struct SSHPROTO *sftp = conn->data->reqdata.proto.ssh;
   CURLcode rc = CURLE_OK;
+  int ret;
   (void)premature; /* not used */
 
   Curl_safefree(sftp->path);
@@ -989,9 +1209,17 @@ CURLcode Curl_sftp_done(struct connectdata *conn, CURLcode status,
   sftp->homedir = NULL;
 
   if (sftp->sftp_handle) {
+#if (LIBSSH2_APINO >= 200706012030)
+    while ((ret = libssh2_sftp_close(sftp->sftp_handle)) ==
+           LIBSSH2_ERROR_EAGAIN);
+    if (ret < 0) {
+      infof(conn->data, "Failed to close libssh2 file\n");
+    }
+#else /* !(LIBSSH2_APINO >= 200706012030) */
     if (libssh2_sftp_close(sftp->sftp_handle) < 0) {
       infof(conn->data, "Failed to close libssh2 file\n");
     }
+#endif /* !(LIBSSH2_APINO >= 200706012030) */
   }
 
   /* Before we shut down, see if there are any post-quote commands to send: */
@@ -1007,13 +1235,26 @@ CURLcode Curl_sftp_done(struct connectdata *conn, CURLcode status,
   }
 
   if (sftp->ssh_channel) {
+#if (LIBSSH2_APINO >= 200706012030)
+    while ((ret = libssh2_channel_close(sftp->ssh_channel)) ==
+           LIBSSH2_ERROR_EAGAIN);
+    if (ret < 0) {
+      infof(conn->data, "Failed to stop libssh2 channel subsystem\n");
+    }
+#else /* !(LIBSSH2_APINO >= 200706012030) */
     if (libssh2_channel_close(sftp->ssh_channel) < 0) {
       infof(conn->data, "Failed to stop libssh2 channel subsystem\n");
     }
+#endif /* !(LIBSSH2_APINO >= 200706012030) */
   }
 
   if (sftp->ssh_session) {
+#if (LIBSSH2_APINO >= 200706012030)
+    while (libssh2_session_disconnect(sftp->ssh_session, "Shutdown") ==
+           LIBSSH2_ERROR_EAGAIN);
+#else /* !(LIBSSH2_APINO >= 200706012030) */
     libssh2_session_disconnect(sftp->ssh_session, "Shutdown");
+#endif /* !(LIBSSH2_APINO >= 200706012030) */
     libssh2_session_free(sftp->ssh_session);
     sftp->ssh_session = NULL;
   }
@@ -1034,7 +1275,7 @@ ssize_t Curl_sftp_send(struct connectdata *conn, int sockindex,
   ssize_t nwrite;   /* libssh2_sftp_write() used to return size_t in 0.14
                        but is changed to ssize_t in 0.15! */
 
-#ifdef LIBSSH2SFTP_EAGAIN
+#if defined(LIBSSH2SFTP_EAGAIN) && (LIBSSH2_APINO < 200706012030)
   /* we prefer the non-blocking API but that didn't exist previously */
   nwrite = (ssize_t)
     libssh2_sftp_writenb(conn->data->reqdata.proto.ssh->sftp_handle, mem, len);
@@ -1190,6 +1431,7 @@ static CURLcode sftp_sendquote(struct connectdata *conn,
   long err;
   struct SessionHandle *data = conn->data;
   LIBSSH2_SFTP *sftp_session = data->reqdata.proto.ssh->sftp_session;
+  int ret;
 
   while (item) {
     if (item->data) {
@@ -1244,6 +1486,29 @@ static CURLcode sftp_sendquote(struct connectdata *conn,
                 sftp_libssh2_strerror(err));
           return CURLE_FTP_QUOTE_ERROR;
         }
+#if (LIBSSH2_APINO >= 200706012030)
+        while ((ret = libssh2_sftp_stat(sftp_session,
+                                        path2, &attrs)) ==
+               LIBSSH2_ERROR_EAGAIN);
+        if (ret != 0) { /* get those attributes */
+          err = libssh2_sftp_last_error(sftp_session);
+          free(path1);
+          free(path2);
+          failf(data, "Attempt to get SFTP stats failed: %s",
+                sftp_libssh2_strerror(err));
+          return CURLE_FTP_QUOTE_ERROR;
+        }
+#else /* !(LIBSSH2_APINO >= 200706012030) */
+        if (libssh2_sftp_stat(sftp_session,
+                              path2, &attrs) != 0) { /* get those attributes */
+          err = libssh2_sftp_last_error(sftp_session);
+          free(path1);
+          free(path2);
+          failf(data, "Attempt to get SFTP stats failed: %s",
+                sftp_libssh2_strerror(err));
+          return CURLE_FTP_QUOTE_ERROR;
+        }
+#endif /* !(LIBSSH2_APINO >= 200706012030) */
 
         /* Now set the new attributes... */
         if (curl_strnequal(item->data, "chgrp", 5)) {
@@ -1275,6 +1540,18 @@ static CURLcode sftp_sendquote(struct connectdata *conn,
         }
 
         /* Now send the completed structure... */
+#if (LIBSSH2_APINO >= 200706012030)
+        while ((ret = libssh2_sftp_setstat(sftp_session, path2, &attrs)) ==
+               LIBSSH2_ERROR_EAGAIN);
+        if (ret != 0) {
+          err = libssh2_sftp_last_error(sftp_session);
+          free(path1);
+          free(path2);
+          failf(data, "Attempt to set SFTP stats failed: %s",
+                sftp_libssh2_strerror(err));
+          return CURLE_FTP_QUOTE_ERROR;
+        }
+#else /* !(LIBSSH2_APINO >= 200706012030) */
         if (libssh2_sftp_setstat(sftp_session, path2, &attrs) != 0) {
           err = libssh2_sftp_last_error(sftp_session);
           free(path1);
@@ -1283,6 +1560,7 @@ static CURLcode sftp_sendquote(struct connectdata *conn,
                 sftp_libssh2_strerror(err));
           return CURLE_FTP_QUOTE_ERROR;
         }
+#endif /* !(LIBSSH2_APINO >= 200706012030) */
       }
       else if (curl_strnequal(item->data, "ln ", 3) ||
                curl_strnequal(item->data, "symlink ", 8)) {
@@ -1298,6 +1576,18 @@ static CURLcode sftp_sendquote(struct connectdata *conn,
           free(path1);
           return err;
         }
+#if (LIBSSH2_APINO >= 200706012030)
+        while ((ret = libssh2_sftp_symlink(sftp_session, path1, path2)) ==
+               LIBSSH2_ERROR_EAGAIN);
+        if (ret != 0) {
+          err = libssh2_sftp_last_error(sftp_session);
+          free(path1);
+          free(path2);
+          failf(data, "symlink command failed: %s",
+                sftp_libssh2_strerror(err));
+          return CURLE_FTP_QUOTE_ERROR;
+        }
+#else /* !(LIBSSH2_APINO >= 200706012030) */
         if (libssh2_sftp_symlink(sftp_session, path1, path2) != 0) {
           err = libssh2_sftp_last_error(sftp_session);
           free(path1);
@@ -1306,8 +1596,19 @@ static CURLcode sftp_sendquote(struct connectdata *conn,
                 sftp_libssh2_strerror(err));
           return CURLE_FTP_QUOTE_ERROR;
         }
+#endif /* !(LIBSSH2_APINO >= 200706012030) */
       }
       else if (curl_strnequal(item->data, "mkdir ", 6)) { /* create dir */
+#if (LIBSSH2_APINO >= 200706012030)
+        while ((ret = libssh2_sftp_mkdir(sftp_session, path1, 0744)) ==
+               LIBSSH2_ERROR_EAGAIN);
+        if (ret != 0) {
+          err = libssh2_sftp_last_error(sftp_session);
+          free(path1);
+          failf(data, "mkdir command failed: %s", sftp_libssh2_strerror(err));
+          return CURLE_FTP_QUOTE_ERROR;
+        }
+#else /* !(LIBSSH2_APINO >= 200706012030) */
         if (libssh2_sftp_mkdir(sftp_session, path1, 0744) != 0) {
           err = libssh2_sftp_last_error(sftp_session);
           free(path1);
@@ -1315,6 +1616,7 @@ static CURLcode sftp_sendquote(struct connectdata *conn,
                 sftp_libssh2_strerror(err));
           return CURLE_FTP_QUOTE_ERROR;
         }
+#endif /* !(LIBSSH2_APINO >= 200706012030) */
       }
       else if (curl_strnequal(item->data, "rename ", 7)) { /* rename file */
         /* first param is the source path */
@@ -1328,6 +1630,17 @@ static CURLcode sftp_sendquote(struct connectdata *conn,
           free(path1);
           return err;
         }
+#if (LIBSSH2_APINO >= 200706012030)
+        while ((ret = libssh2_sftp_rename(sftp_session, path1, path2)) ==
+               LIBSSH2_ERROR_EAGAIN);
+        if (ret != 0) {
+          err = libssh2_sftp_last_error(sftp_session);
+          free(path1);
+          free(path2);
+          failf(data, "rename command failed: %s", sftp_libssh2_strerror(err));
+          return CURLE_FTP_QUOTE_ERROR;
+        }
+#else /* !(LIBSSH2_APINO >= 200706012030) */
         if (libssh2_sftp_rename(sftp_session,
                                 path1, path2) != 0) {
           err = libssh2_sftp_last_error(sftp_session);
@@ -1337,8 +1650,19 @@ static CURLcode sftp_sendquote(struct connectdata *conn,
                 sftp_libssh2_strerror(err));
           return CURLE_FTP_QUOTE_ERROR;
         }
+#endif /* !(LIBSSH2_APINO >= 200706012030) */
       }
       else if (curl_strnequal(item->data, "rmdir ", 6)) { /* delete dir */
+#if (LIBSSH2_APINO >= 200706012030)
+        while ((ret = libssh2_sftp_rmdir(sftp_session, path1)) ==
+               LIBSSH2_ERROR_EAGAIN);
+        if (ret != 0) {
+          err = libssh2_sftp_last_error(sftp_session);
+          free(path1);
+          failf(data, "rmdir command failed: %s", sftp_libssh2_strerror(err));
+          return CURLE_FTP_QUOTE_ERROR;
+        }
+#else /* !(LIBSSH2_APINO >= 200706012030) */
         if (libssh2_sftp_rmdir(sftp_session,
                                path1) != 0) {
           err = libssh2_sftp_last_error(sftp_session);
@@ -1347,8 +1671,19 @@ static CURLcode sftp_sendquote(struct connectdata *conn,
                 sftp_libssh2_strerror(err));
           return CURLE_FTP_QUOTE_ERROR;
         }
+#endif /* !(LIBSSH2_APINO >= 200706012030) */
       }
       else if (curl_strnequal(item->data, "rm ", 3)) { /* delete file */
+#if (LIBSSH2_APINO >= 200706012030)
+        while ((ret = libssh2_sftp_unlink(sftp_session, path1)) ==
+               LIBSSH2_ERROR_EAGAIN);
+        if (ret != 0) {
+          err = libssh2_sftp_last_error(sftp_session);
+          free(path1);
+          failf(data, "rm command failed: %s", sftp_libssh2_strerror(err));
+          return CURLE_FTP_QUOTE_ERROR;
+        }
+#else /* !(LIBSSH2_APINO >= 200706012030) */
         if (libssh2_sftp_unlink(sftp_session, path1) != 0) {
           err = libssh2_sftp_last_error(sftp_session);
           free(path1);
@@ -1356,6 +1691,7 @@ static CURLcode sftp_sendquote(struct connectdata *conn,
                 sftp_libssh2_strerror(err));
           return CURLE_FTP_QUOTE_ERROR;
         }
+#endif /* !(LIBSSH2_APINO >= 200706012030) */
       }
 
       if (path1)
@@ -1381,7 +1717,7 @@ ssize_t Curl_sftp_recv(struct connectdata *conn, int sockindex,
 
   /* libssh2_sftp_read() returns size_t !*/
 
-#ifdef LIBSSH2SFTP_EAGAIN
+#if defined(LIBSSH2SFTP_EAGAIN) && (LIBSSH2_APINO < 200706012030)
   /* we prefer the non-blocking API but that didn't exist previously */
   nread = (ssize_t)
     libssh2_sftp_readnb(conn->data->reqdata.proto.ssh->sftp_handle, mem, len);