ssh_statemach_act() is now modified to loop over the switch() to perform as
authorDaniel Stenberg <daniel@haxx.se>
Mon, 11 Jan 2010 23:10:53 +0000 (23:10 +0000)
committerDaniel Stenberg <daniel@haxx.se>
Mon, 11 Jan 2010 23:10:53 +0000 (23:10 +0000)
much as possible in one go, as long as it doesn't block and hasn't reached the
end of the state machine.
This avoids spurious -1 returns from curl_multi_fdset() simply because
previously it would return from this function without anything in EWOUDLBLOCK
and thus basically it wasn't actually waiting for anything!!

lib/ssh.c

index a93e440..71a8de3 100644 (file)
--- a/lib/ssh.c
+++ b/lib/ssh.c
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -459,10 +459,10 @@ static int sshkeycallback(CURL *easy,
 #endif
 
 /*
- * ssh_statemach_act() runs the SSH statemachine "one round" and returns.  The
- * data the pointer 'block' points to will be set to TRUE if the libssh2
- * function returns LIBSSH2_ERROR_EAGAIN meaning it wants to be called again
- * when the socket is ready
+ * ssh_statemach_act() runs the SSH state machine as far as it can without
+ * blocking and without reaching the end.  The data the pointer 'block' points
+ * to will be set to TRUE if the libssh2 function returns LIBSSH2_ERROR_EAGAIN
+ * meaning it wants to be called again when the socket is ready
  */
 
 static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
@@ -481,1194 +481,1181 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
   int seekerr = CURL_SEEKFUNC_OK;
   *block = 0; /* we're not blocking by default */
 
-  switch(sshc->state) {
-  case SSH_S_STARTUP:
-    sshc->secondCreateDirs = 0;
-    sshc->nextstate = SSH_NO_STATE;
-    sshc->actualcode = CURLE_OK;
+  do {
 
-    rc = libssh2_session_startup(sshc->ssh_session, sock);
-    if(rc == LIBSSH2_ERROR_EAGAIN) {
-      break;
-    }
-    else if(rc) {
-      failf(data, "Failure establishing ssh session");
-      state(conn, SSH_SESSION_FREE);
-      sshc->actualcode = CURLE_FAILED_INIT;
-      break;
-    }
+    switch(sshc->state) {
+    case SSH_S_STARTUP:
+      sshc->secondCreateDirs = 0;
+      sshc->nextstate = SSH_NO_STATE;
+      sshc->actualcode = CURLE_OK;
+
+      rc = libssh2_session_startup(sshc->ssh_session, sock);
+      if(rc == LIBSSH2_ERROR_EAGAIN) {
+        break;
+      }
+      else if(rc) {
+        failf(data, "Failure establishing ssh session");
+        state(conn, SSH_SESSION_FREE);
+        sshc->actualcode = CURLE_FAILED_INIT;
+        break;
+      }
 
-    /* Set libssh2 to non-blocking, since everything internally is
-       non-blocking */
-    libssh2_session_set_blocking(sshc->ssh_session, 0);
+      /* Set libssh2 to non-blocking, since everything internally is
+         non-blocking */
+      libssh2_session_set_blocking(sshc->ssh_session, 0);
 
-    state(conn, SSH_HOSTKEY);
+      state(conn, SSH_HOSTKEY);
 
-    /* fall-through */
-  case SSH_HOSTKEY:
+      /* fall-through */
+    case SSH_HOSTKEY:
 
 #ifdef CURL_LIBSSH2_DEBUG
-    /*
-     * Before we authenticate we should check the hostkey's fingerprint
-     * against our known hosts. How that is handled (reading from file,
-     * whatever) is up to us. As for know not much is implemented, besides
-     * showing how to get the fingerprint.
-     */
-    fingerprint = libssh2_hostkey_hash(sshc->ssh_session,
-                                       LIBSSH2_HOSTKEY_HASH_MD5);
-
-    /* The fingerprint points to static storage (!), don't free() it. */
-    infof(data, "Fingerprint: ");
-    for (rc = 0; rc < 16; rc++) {
-      infof(data, "%02X ", (unsigned char) fingerprint[rc]);
-    }
-    infof(data, "\n");
-#endif /* CURL_LIBSSH2_DEBUG */
+      /*
+       * Before we authenticate we should check the hostkey's fingerprint
+       * against our known hosts. How that is handled (reading from file,
+       * whatever) is up to us. As for know not much is implemented, besides
+       * showing how to get the fingerprint.
+       */
+      fingerprint = libssh2_hostkey_hash(sshc->ssh_session,
+                                         LIBSSH2_HOSTKEY_HASH_MD5);
 
-    /* Before we authenticate we check the hostkey's MD5 fingerprint
-     * against a known fingerprint, if available.  This implementation pulls
-     * it from the curl option.
-     */
-    if(data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5] &&
-       strlen(data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]) == 32) {
-      char buf[33];
-      host_public_key_md5 = libssh2_hostkey_hash(sshc->ssh_session,
-                                                 LIBSSH2_HOSTKEY_HASH_MD5);
-      for (i = 0; i < 16; i++)
-        snprintf(&buf[i*2], 3, "%02x",
-                 (unsigned char) host_public_key_md5[i]);
-      if(!strequal(buf, data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5])) {
-        failf(data,
-              "Denied establishing ssh session: mismatch md5 fingerprint. "
-              "Remote %s is not equal to %s",
-              buf, data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]);
-        state(conn, SSH_SESSION_FREE);
-        sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
-        break;
+      /* The fingerprint points to static storage (!), don't free() it. */
+      infof(data, "Fingerprint: ");
+      for (rc = 0; rc < 16; rc++) {
+        infof(data, "%02X ", (unsigned char) fingerprint[rc]);
       }
-    }
+      infof(data, "\n");
+#endif /* CURL_LIBSSH2_DEBUG */
 
-#ifdef HAVE_LIBSSH2_KNOWNHOST_API
-    if(data->set.str[STRING_SSH_KNOWNHOSTS]) {
-      /* we're asked to verify the host against a file */
-      int keytype;
-      size_t keylen;
-      const char *remotekey = libssh2_session_hostkey(sshc->ssh_session,
-                                                      &keylen, &keytype);
-      int keycheck;
-      int keybit;
-
-      if(remotekey) {
-        /*
-         * A subject to figure out is what host name we need to pass in here.
-         * What host name does OpenSSH store in its file if an IDN name is
-         * used?
-         */
-        struct libssh2_knownhost *host;
-        enum curl_khmatch keymatch;
-        curl_sshkeycallback func =
-          data->set.ssh_keyfunc?data->set.ssh_keyfunc:sshkeycallback;
-        struct curl_khkey knownkey;
-        struct curl_khkey *knownkeyp = NULL;
-        struct curl_khkey foundkey;
-
-        keybit = (keytype == LIBSSH2_HOSTKEY_TYPE_RSA)?
-          LIBSSH2_KNOWNHOST_KEY_SSHRSA:LIBSSH2_KNOWNHOST_KEY_SSHDSS;
-
-        keycheck = libssh2_knownhost_check(sshc->kh,
-                                           conn->host.name,
-                                           remotekey, keylen,
-                                           LIBSSH2_KNOWNHOST_TYPE_PLAIN|
-                                           LIBSSH2_KNOWNHOST_KEYENC_RAW|
-                                           keybit,
-                                           &host);
-
-        infof(data, "SSH host check: %d, key: %s\n", keycheck,
-              (keycheck <= LIBSSH2_KNOWNHOST_CHECK_MISMATCH)?
-              host->key:"<none>");
-
-        /* setup 'knownkey' */
-        if(keycheck <= LIBSSH2_KNOWNHOST_CHECK_MISMATCH) {
-          knownkey.key = host->key;
-          knownkey.len = 0;
-          knownkey.keytype = (keytype == LIBSSH2_HOSTKEY_TYPE_RSA)?
-            CURLKHTYPE_RSA : CURLKHTYPE_DSS;
-          knownkeyp = &knownkey;
+      /* Before we authenticate we check the hostkey's MD5 fingerprint
+       * against a known fingerprint, if available.  This implementation pulls
+       * it from the curl option.
+       */
+      if(data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5] &&
+         strlen(data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]) == 32) {
+        char buf[33];
+        host_public_key_md5 = libssh2_hostkey_hash(sshc->ssh_session,
+                                                   LIBSSH2_HOSTKEY_HASH_MD5);
+        for (i = 0; i < 16; i++)
+          snprintf(&buf[i*2], 3, "%02x",
+                   (unsigned char) host_public_key_md5[i]);
+        if(!strequal(buf, data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5])) {
+          failf(data,
+                "Denied establishing ssh session: mismatch md5 fingerprint. "
+                "Remote %s is not equal to %s",
+                buf, data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]);
+          state(conn, SSH_SESSION_FREE);
+          sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
+          break;
         }
+      }
 
-        /* setup 'foundkey' */
-        foundkey.key = remotekey;
-        foundkey.len = keylen;
-        foundkey.keytype = (keytype == LIBSSH2_HOSTKEY_TYPE_RSA)?
-          CURLKHTYPE_RSA : CURLKHTYPE_DSS;
-
-        /*
-         * if any of the LIBSSH2_KNOWNHOST_CHECK_* defines and the
-         * curl_khmatch enum are ever modified, we need to introduce a
-         * translation table here!
-         */
-        keymatch = (enum curl_khmatch)keycheck;
+#ifdef HAVE_LIBSSH2_KNOWNHOST_API
+      if(data->set.str[STRING_SSH_KNOWNHOSTS]) {
+        /* we're asked to verify the host against a file */
+        int keytype;
+        size_t keylen;
+        const char *remotekey = libssh2_session_hostkey(sshc->ssh_session,
+                                                        &keylen, &keytype);
+        int keycheck;
+        int keybit;
+
+        if(remotekey) {
+          /*
+           * A subject to figure out is what host name we need to pass in here.
+           * What host name does OpenSSH store in its file if an IDN name is
+           * used?
+           */
+          struct libssh2_knownhost *host;
+          enum curl_khmatch keymatch;
+          curl_sshkeycallback func =
+            data->set.ssh_keyfunc?data->set.ssh_keyfunc:sshkeycallback;
+          struct curl_khkey knownkey;
+          struct curl_khkey *knownkeyp = NULL;
+          struct curl_khkey foundkey;
+
+          keybit = (keytype == LIBSSH2_HOSTKEY_TYPE_RSA)?
+            LIBSSH2_KNOWNHOST_KEY_SSHRSA:LIBSSH2_KNOWNHOST_KEY_SSHDSS;
+
+          keycheck = libssh2_knownhost_check(sshc->kh,
+                                             conn->host.name,
+                                             remotekey, keylen,
+                                             LIBSSH2_KNOWNHOST_TYPE_PLAIN|
+                                             LIBSSH2_KNOWNHOST_KEYENC_RAW|
+                                             keybit,
+                                             &host);
+
+          infof(data, "SSH host check: %d, key: %s\n", keycheck,
+                (keycheck <= LIBSSH2_KNOWNHOST_CHECK_MISMATCH)?
+                host->key:"<none>");
+
+          /* setup 'knownkey' */
+          if(keycheck <= LIBSSH2_KNOWNHOST_CHECK_MISMATCH) {
+            knownkey.key = host->key;
+            knownkey.len = 0;
+            knownkey.keytype = (keytype == LIBSSH2_HOSTKEY_TYPE_RSA)?
+              CURLKHTYPE_RSA : CURLKHTYPE_DSS;
+            knownkeyp = &knownkey;
+          }
 
-        /* Ask the callback how to behave */
-        rc = func(data, knownkeyp, /* from the knownhosts file */
-                  &foundkey, /* from the remote host */
-                  keymatch, data->set.ssh_keyfunc_userp);
-      }
-      else
-        /* no remotekey means failure! */
-        rc = CURLKHSTAT_REJECT;
+          /* setup 'foundkey' */
+          foundkey.key = remotekey;
+          foundkey.len = keylen;
+          foundkey.keytype = (keytype == LIBSSH2_HOSTKEY_TYPE_RSA)?
+            CURLKHTYPE_RSA : CURLKHTYPE_DSS;
 
-      switch(rc) {
-      default: /* unknown return codes will equal reject */
-      case CURLKHSTAT_REJECT:
-        state(conn, SSH_SESSION_FREE);
-      case CURLKHSTAT_DEFER:
-        /* DEFER means bail out but keep the SSH_HOSTKEY state */
-        result = sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
-        break;
-      case CURLKHSTAT_FINE:
-      case CURLKHSTAT_FINE_ADD_TO_FILE:
-        /* proceed */
-        if(keycheck != LIBSSH2_KNOWNHOST_CHECK_MATCH) {
-          /* the found host+key didn't match but has been told to be fine
-             anyway so we add it in memory */
-          int addrc = libssh2_knownhost_add(sshc->kh,
-                                            conn->host.name, NULL,
-                                            remotekey, keylen,
-                                            LIBSSH2_KNOWNHOST_TYPE_PLAIN|
-                                            LIBSSH2_KNOWNHOST_KEYENC_RAW|
-                                            keybit, NULL);
-          if(addrc)
-            infof(data, "Warning adding the known host %s failed!\n",
-                  conn->host.name);
-          else if(rc == CURLKHSTAT_FINE_ADD_TO_FILE) {
-            /* now we write the entire in-memory list of known hosts to the
-               known_hosts file */
-            int wrc =
-              libssh2_knownhost_writefile(sshc->kh,
-                                          data->set.str[STRING_SSH_KNOWNHOSTS],
-                                          LIBSSH2_KNOWNHOST_FILE_OPENSSH);
-            if(wrc) {
-              infof(data, "Warning, writing %s failed!\n",
-                    data->set.str[STRING_SSH_KNOWNHOSTS]);
+          /*
+           * if any of the LIBSSH2_KNOWNHOST_CHECK_* defines and the
+           * curl_khmatch enum are ever modified, we need to introduce a
+           * translation table here!
+           */
+          keymatch = (enum curl_khmatch)keycheck;
+
+          /* Ask the callback how to behave */
+          rc = func(data, knownkeyp, /* from the knownhosts file */
+                    &foundkey, /* from the remote host */
+                    keymatch, data->set.ssh_keyfunc_userp);
+        }
+        else
+          /* no remotekey means failure! */
+          rc = CURLKHSTAT_REJECT;
+
+        switch(rc) {
+        default: /* unknown return codes will equal reject */
+        case CURLKHSTAT_REJECT:
+          state(conn, SSH_SESSION_FREE);
+        case CURLKHSTAT_DEFER:
+          /* DEFER means bail out but keep the SSH_HOSTKEY state */
+          result = sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
+          break;
+        case CURLKHSTAT_FINE:
+        case CURLKHSTAT_FINE_ADD_TO_FILE:
+          /* proceed */
+          if(keycheck != LIBSSH2_KNOWNHOST_CHECK_MATCH) {
+            /* the found host+key didn't match but has been told to be fine
+               anyway so we add it in memory */
+            int addrc = libssh2_knownhost_add(sshc->kh,
+                                              conn->host.name, NULL,
+                                              remotekey, keylen,
+                                              LIBSSH2_KNOWNHOST_TYPE_PLAIN|
+                                              LIBSSH2_KNOWNHOST_KEYENC_RAW|
+                                              keybit, NULL);
+            if(addrc)
+              infof(data, "Warning adding the known host %s failed!\n",
+                    conn->host.name);
+            else if(rc == CURLKHSTAT_FINE_ADD_TO_FILE) {
+              /* now we write the entire in-memory list of known hosts to the
+                 known_hosts file */
+              int wrc =
+                libssh2_knownhost_writefile(sshc->kh,
+                                            data->set.str[STRING_SSH_KNOWNHOSTS],
+                                            LIBSSH2_KNOWNHOST_FILE_OPENSSH);
+              if(wrc) {
+                infof(data, "Warning, writing %s failed!\n",
+                      data->set.str[STRING_SSH_KNOWNHOSTS]);
+              }
             }
           }
+          break;
         }
-        break;
       }
-    }
 #endif /* HAVE_LIBSSH2_KNOWNHOST_API */
 
-    state(conn, SSH_AUTHLIST);
-    break;
+      state(conn, SSH_AUTHLIST);
+      break;
 
-  case SSH_AUTHLIST:
-    /*
-     * Figure out authentication methods
-     * NB: As soon as we have provided a username to an openssh server we
-     * must never change it later. Thus, always specify the correct username
-     * here, even though the libssh2 docs kind of indicate that it should be
-     * possible to get a 'generic' list (not user-specific) of authentication
-     * methods, presumably with a blank username. That won't work in my
-     * experience.
-     * So always specify it here.
-     */
-    sshc->authlist = libssh2_userauth_list(sshc->ssh_session,
-                                           conn->user,
-                                           strlen(conn->user));
-
-    if(!sshc->authlist) {
-      if((err = libssh2_session_last_errno(sshc->ssh_session)) ==
-         LIBSSH2_ERROR_EAGAIN) {
-        rc = LIBSSH2_ERROR_EAGAIN;
-        break;
-      }
-      else {
-        state(conn, SSH_SESSION_FREE);
-        sshc->actualcode = libssh2_session_error_to_CURLE(err);
-        break;
+    case SSH_AUTHLIST:
+      /*
+       * Figure out authentication methods
+       * NB: As soon as we have provided a username to an openssh server we
+       * must never change it later. Thus, always specify the correct username
+       * here, even though the libssh2 docs kind of indicate that it should be
+       * possible to get a 'generic' list (not user-specific) of authentication
+       * methods, presumably with a blank username. That won't work in my
+       * experience.
+       * So always specify it here.
+       */
+      sshc->authlist = libssh2_userauth_list(sshc->ssh_session,
+                                             conn->user,
+                                             strlen(conn->user));
+
+      if(!sshc->authlist) {
+        if((err = libssh2_session_last_errno(sshc->ssh_session)) ==
+           LIBSSH2_ERROR_EAGAIN) {
+          rc = LIBSSH2_ERROR_EAGAIN;
+          break;
+        }
+        else {
+          state(conn, SSH_SESSION_FREE);
+          sshc->actualcode = libssh2_session_error_to_CURLE(err);
+          break;
+        }
       }
-    }
-    infof(data, "SSH authentication methods available: %s\n", sshc->authlist);
+      infof(data, "SSH authentication methods available: %s\n", sshc->authlist);
 
-    state(conn, SSH_AUTH_PKEY_INIT);
-    break;
+      state(conn, SSH_AUTH_PKEY_INIT);
+      break;
 
-  case SSH_AUTH_PKEY_INIT:
-    /*
-     * Check the supported auth types in the order I feel is most secure
-     * with the requested type of authentication
-     */
-    sshc->authed = FALSE;
+    case SSH_AUTH_PKEY_INIT:
+      /*
+       * Check the supported auth types in the order I feel is most secure
+       * with the requested type of authentication
+       */
+      sshc->authed = FALSE;
 
-    if((data->set.ssh_auth_types & CURLSSH_AUTH_PUBLICKEY) &&
-       (strstr(sshc->authlist, "publickey") != NULL)) {
-      char *home;
+      if((data->set.ssh_auth_types & CURLSSH_AUTH_PUBLICKEY) &&
+         (strstr(sshc->authlist, "publickey") != NULL)) {
+        char *home;
 
-      sshc->rsa_pub = sshc->rsa = NULL;
+        sshc->rsa_pub = sshc->rsa = NULL;
 
-      /* To ponder about: should really the lib be messing about with the
-         HOME environment variable etc? */
-      home = curl_getenv("HOME");
+        /* To ponder about: should really the lib be messing about with the
+           HOME environment variable etc? */
+        home = curl_getenv("HOME");
 
-      if(data->set.str[STRING_SSH_PUBLIC_KEY])
-        sshc->rsa_pub = aprintf("%s", data->set.str[STRING_SSH_PUBLIC_KEY]);
-      else if(home)
-        sshc->rsa_pub = aprintf("%s/.ssh/id_dsa.pub", home);
-      else
-        /* as a final resort, try current dir! */
-        sshc->rsa_pub = strdup("id_dsa.pub");
+        if(data->set.str[STRING_SSH_PUBLIC_KEY])
+          sshc->rsa_pub = aprintf("%s", data->set.str[STRING_SSH_PUBLIC_KEY]);
+        else if(home)
+          sshc->rsa_pub = aprintf("%s/.ssh/id_dsa.pub", home);
+        else
+          /* as a final resort, try current dir! */
+          sshc->rsa_pub = strdup("id_dsa.pub");
 
-      if(sshc->rsa_pub == NULL) {
-        Curl_safefree(home);
-        home = NULL;
-        state(conn, SSH_SESSION_FREE);
-        sshc->actualcode = CURLE_OUT_OF_MEMORY;
-        break;
-      }
+        if(sshc->rsa_pub == NULL) {
+          Curl_safefree(home);
+          home = NULL;
+          state(conn, SSH_SESSION_FREE);
+          sshc->actualcode = CURLE_OUT_OF_MEMORY;
+          break;
+        }
 
-      if(data->set.str[STRING_SSH_PRIVATE_KEY])
-        sshc->rsa = aprintf("%s", data->set.str[STRING_SSH_PRIVATE_KEY]);
-      else if(home)
-        sshc->rsa = aprintf("%s/.ssh/id_dsa", home);
-      else
-        /* as a final resort, try current dir! */
-        sshc->rsa = strdup("id_dsa");
+        if(data->set.str[STRING_SSH_PRIVATE_KEY])
+          sshc->rsa = aprintf("%s", data->set.str[STRING_SSH_PRIVATE_KEY]);
+        else if(home)
+          sshc->rsa = aprintf("%s/.ssh/id_dsa", home);
+        else
+          /* as a final resort, try current dir! */
+          sshc->rsa = strdup("id_dsa");
+
+        if(sshc->rsa == NULL) {
+          Curl_safefree(home);
+          home = NULL;
+          Curl_safefree(sshc->rsa_pub);
+          sshc->rsa_pub = NULL;
+          state(conn, SSH_SESSION_FREE);
+          sshc->actualcode = CURLE_OUT_OF_MEMORY;
+          break;
+        }
+
+        sshc->passphrase = data->set.str[STRING_KEY_PASSWD];
+        if(!sshc->passphrase)
+          sshc->passphrase = "";
 
-      if(sshc->rsa == NULL) {
         Curl_safefree(home);
         home = NULL;
-        Curl_safefree(sshc->rsa_pub);
-        sshc->rsa_pub = NULL;
-        state(conn, SSH_SESSION_FREE);
-        sshc->actualcode = CURLE_OUT_OF_MEMORY;
-        break;
-      }
-
-      sshc->passphrase = data->set.str[STRING_KEY_PASSWD];
-      if(!sshc->passphrase)
-        sshc->passphrase = "";
 
-      Curl_safefree(home);
-      home = NULL;
+        infof(data, "Using ssh public key file %s\n", sshc->rsa_pub);
+        infof(data, "Using ssh private key file %s\n", sshc->rsa);
 
-      infof(data, "Using ssh public key file %s\n", sshc->rsa_pub);
-      infof(data, "Using ssh private key file %s\n", sshc->rsa);
-
-      state(conn, SSH_AUTH_PKEY);
-    }
-    else {
-      state(conn, SSH_AUTH_PASS_INIT);
-    }
-    break;
-
-  case SSH_AUTH_PKEY:
-    /* The function below checks if the files exists, no need to stat() here.
-     */
-    rc = libssh2_userauth_publickey_fromfile(sshc->ssh_session,
-                                             conn->user, sshc->rsa_pub,
-                                             sshc->rsa, sshc->passphrase);
-    if(rc == LIBSSH2_ERROR_EAGAIN) {
+        state(conn, SSH_AUTH_PKEY);
+      }
+      else {
+        state(conn, SSH_AUTH_PASS_INIT);
+      }
       break;
-    }
 
-    Curl_safefree(sshc->rsa_pub);
-    sshc->rsa_pub = NULL;
-    Curl_safefree(sshc->rsa);
-    sshc->rsa = NULL;
-
-    if(rc == 0) {
-      sshc->authed = TRUE;
-      infof(data, "Initialized SSH public key authentication\n");
-      state(conn, SSH_AUTH_DONE);
-    }
-    else {
-      char *err_msg;
-      (void)libssh2_session_last_error(sshc->ssh_session,
-                                       &err_msg, NULL, 0);
-      infof(data, "SSH public key authentication failed: %s\n", err_msg);
-      state(conn, SSH_AUTH_PASS_INIT);
-    }
-    break;
+    case SSH_AUTH_PKEY:
+      /* The function below checks if the files exists, no need to stat() here.
+       */
+      rc = libssh2_userauth_publickey_fromfile(sshc->ssh_session,
+                                               conn->user, sshc->rsa_pub,
+                                               sshc->rsa, sshc->passphrase);
+      if(rc == LIBSSH2_ERROR_EAGAIN) {
+        break;
+      }
 
-  case SSH_AUTH_PASS_INIT:
-    if((data->set.ssh_auth_types & CURLSSH_AUTH_PASSWORD) &&
-       (strstr(sshc->authlist, "password") != NULL)) {
-      state(conn, SSH_AUTH_PASS);
-    }
-    else {
-      state(conn, SSH_AUTH_HOST_INIT);
-    }
-    break;
+      Curl_safefree(sshc->rsa_pub);
+      sshc->rsa_pub = NULL;
+      Curl_safefree(sshc->rsa);
+      sshc->rsa = NULL;
 
-  case SSH_AUTH_PASS:
-    rc = libssh2_userauth_password(sshc->ssh_session, conn->user,
-                                   conn->passwd);
-    if(rc == LIBSSH2_ERROR_EAGAIN) {
+      if(rc == 0) {
+        sshc->authed = TRUE;
+        infof(data, "Initialized SSH public key authentication\n");
+        state(conn, SSH_AUTH_DONE);
+      }
+      else {
+        char *err_msg;
+        (void)libssh2_session_last_error(sshc->ssh_session,
+                                         &err_msg, NULL, 0);
+        infof(data, "SSH public key authentication failed: %s\n", err_msg);
+        state(conn, SSH_AUTH_PASS_INIT);
+      }
       break;
-    }
-    else if(rc == 0) {
-      sshc->authed = TRUE;
-      infof(data, "Initialized password authentication\n");
-      state(conn, SSH_AUTH_DONE);
-    }
-    else {
-      state(conn, SSH_AUTH_HOST_INIT);
-    }
-    break;
-
-  case SSH_AUTH_HOST_INIT:
-    if((data->set.ssh_auth_types & CURLSSH_AUTH_HOST) &&
-       (strstr(sshc->authlist, "hostbased") != NULL)) {
-      state(conn, SSH_AUTH_HOST);
-    }
-    else {
-      state(conn, SSH_AUTH_KEY_INIT);
-    }
-    break;
-
-  case SSH_AUTH_HOST:
-    state(conn, SSH_AUTH_KEY_INIT);
-    break;
-
-  case SSH_AUTH_KEY_INIT:
-    if((data->set.ssh_auth_types & CURLSSH_AUTH_KEYBOARD)
-       && (strstr(sshc->authlist, "keyboard-interactive") != NULL)) {
-      state(conn, SSH_AUTH_KEY);
-    }
-    else {
-      state(conn, SSH_AUTH_DONE);
-    }
-    break;
 
-  case SSH_AUTH_KEY:
-    /* Authentication failed. Continue with keyboard-interactive now. */
-    rc = libssh2_userauth_keyboard_interactive_ex(sshc->ssh_session,
-                                                  conn->user,
-                                                  strlen(conn->user),
-                                                  &kbd_callback);
-    if(rc == LIBSSH2_ERROR_EAGAIN) {
+    case SSH_AUTH_PASS_INIT:
+      if((data->set.ssh_auth_types & CURLSSH_AUTH_PASSWORD) &&
+         (strstr(sshc->authlist, "password") != NULL)) {
+        state(conn, SSH_AUTH_PASS);
+      }
+      else {
+        state(conn, SSH_AUTH_HOST_INIT);
+      }
       break;
-    }
-    else if(rc == 0) {
-      sshc->authed = TRUE;
-      infof(data, "Initialized keyboard interactive authentication\n");
-    }
-    state(conn, SSH_AUTH_DONE);
-    break;
 
-  case SSH_AUTH_DONE:
-    if(!sshc->authed) {
-      failf(data, "Authentication failure");
-      state(conn, SSH_SESSION_FREE);
-      sshc->actualcode = CURLE_LOGIN_DENIED;
+    case SSH_AUTH_PASS:
+      rc = libssh2_userauth_password(sshc->ssh_session, conn->user,
+                                     conn->passwd);
+      if(rc == LIBSSH2_ERROR_EAGAIN) {
+        break;
+      }
+      else if(rc == 0) {
+        sshc->authed = TRUE;
+        infof(data, "Initialized password authentication\n");
+        state(conn, SSH_AUTH_DONE);
+      }
+      else {
+        state(conn, SSH_AUTH_HOST_INIT);
+      }
       break;
-    }
 
-    /*
-     * At this point we have an authenticated ssh session.
-     */
-    infof(data, "Authentication complete\n");
-
-    Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSH is connected */
+    case SSH_AUTH_HOST_INIT:
+      if((data->set.ssh_auth_types & CURLSSH_AUTH_HOST) &&
+         (strstr(sshc->authlist, "hostbased") != NULL)) {
+        state(conn, SSH_AUTH_HOST);
+      }
+      else {
+        state(conn, SSH_AUTH_KEY_INIT);
+      }
+      break;
 
-    conn->sockfd = sock;
-    conn->writesockfd = CURL_SOCKET_BAD;
+    case SSH_AUTH_HOST:
+      state(conn, SSH_AUTH_KEY_INIT);
+      break;
 
-    if(conn->protocol == PROT_SFTP) {
-      state(conn, SSH_SFTP_INIT);
+    case SSH_AUTH_KEY_INIT:
+      if((data->set.ssh_auth_types & CURLSSH_AUTH_KEYBOARD)
+         && (strstr(sshc->authlist, "keyboard-interactive") != NULL)) {
+        state(conn, SSH_AUTH_KEY);
+      }
+      else {
+        state(conn, SSH_AUTH_DONE);
+      }
       break;
-    }
-    infof(data, "SSH CONNECT phase done\n");
-    state(conn, SSH_STOP);
-    break;
 
-  case SSH_SFTP_INIT:
-    /*
-     * Start the libssh2 sftp session
-     */
-    sshc->sftp_session = libssh2_sftp_init(sshc->ssh_session);
-    if(!sshc->sftp_session) {
-      if(libssh2_session_last_errno(sshc->ssh_session) ==
-         LIBSSH2_ERROR_EAGAIN) {
-        rc = LIBSSH2_ERROR_EAGAIN;
+    case SSH_AUTH_KEY:
+      /* Authentication failed. Continue with keyboard-interactive now. */
+      rc = libssh2_userauth_keyboard_interactive_ex(sshc->ssh_session,
+                                                    conn->user,
+                                                    strlen(conn->user),
+                                                    &kbd_callback);
+      if(rc == LIBSSH2_ERROR_EAGAIN) {
         break;
       }
-      else {
-        char *err_msg;
+      else if(rc == 0) {
+        sshc->authed = TRUE;
+        infof(data, "Initialized keyboard interactive authentication\n");
+      }
+      state(conn, SSH_AUTH_DONE);
+      break;
 
-        (void)libssh2_session_last_error(sshc->ssh_session,
-                                         &err_msg, NULL, 0);
-        failf(data, "Failure initializing sftp session: %s", err_msg);
+    case SSH_AUTH_DONE:
+      if(!sshc->authed) {
+        failf(data, "Authentication failure");
         state(conn, SSH_SESSION_FREE);
-        sshc->actualcode = CURLE_FAILED_INIT;
+        sshc->actualcode = CURLE_LOGIN_DENIED;
         break;
       }
-    }
-    state(conn, SSH_SFTP_REALPATH);
-    break;
 
-  case SSH_SFTP_REALPATH:
-  {
-    char tempHome[PATH_MAX];
+      /*
+       * At this point we have an authenticated ssh session.
+       */
+      infof(data, "Authentication complete\n");
 
-    /*
-     * Get the "home" directory
-     */
-    rc = libssh2_sftp_realpath(sshc->sftp_session, ".",
-                               tempHome, PATH_MAX-1);
-    if(rc == LIBSSH2_ERROR_EAGAIN) {
-      break;
-    }
-    else if(rc > 0) {
-      /* It seems that this string is not always NULL terminated */
-      tempHome[rc] = '\0';
-      sshc->homedir = strdup(tempHome);
-      if(!sshc->homedir) {
-        state(conn, SSH_SFTP_CLOSE);
-        sshc->actualcode = CURLE_OUT_OF_MEMORY;
+      Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSH is connected */
+
+      conn->sockfd = sock;
+      conn->writesockfd = CURL_SOCKET_BAD;
+
+      if(conn->protocol == PROT_SFTP) {
+        state(conn, SSH_SFTP_INIT);
         break;
       }
-    }
-    else {
-      /* Return the error type */
-      err = libssh2_sftp_last_error(sshc->sftp_session);
-      result = sftp_libssh2_error_to_CURLE(err);
-      sshc->actualcode = result?result:CURLE_SSH;
-      DEBUGF(infof(data, "error = %d makes libcurl = %d\n", err, result));
+      infof(data, "SSH CONNECT phase done\n");
       state(conn, SSH_STOP);
       break;
-    }
-  }
-  /* This is the last step in the SFTP connect phase. Do note that while
-     we get the homedir here, we get the "workingpath" in the DO action
-     since the homedir will remain the same between request but the
-     working path will not. */
-  DEBUGF(infof(data, "SSH CONNECT phase done\n"));
-  state(conn, SSH_STOP);
-  break;
 
-  case SSH_SFTP_QUOTE_INIT:
+    case SSH_SFTP_INIT:
+      /*
+       * Start the libssh2 sftp session
+       */
+      sshc->sftp_session = libssh2_sftp_init(sshc->ssh_session);
+      if(!sshc->sftp_session) {
+        if(libssh2_session_last_errno(sshc->ssh_session) ==
+           LIBSSH2_ERROR_EAGAIN) {
+          rc = LIBSSH2_ERROR_EAGAIN;
+          break;
+        }
+        else {
+          char *err_msg;
 
-    result = ssh_getworkingpath(conn, sshc->homedir, &sftp_scp->path);
-    if(result) {
-      sshc->actualcode = result;
-      state(conn, SSH_STOP);
+          (void)libssh2_session_last_error(sshc->ssh_session,
+                                           &err_msg, NULL, 0);
+          failf(data, "Failure initializing sftp session: %s", err_msg);
+          state(conn, SSH_SESSION_FREE);
+          sshc->actualcode = CURLE_FAILED_INIT;
+          break;
+        }
+      }
+      state(conn, SSH_SFTP_REALPATH);
       break;
-    }
-
-    if(data->set.quote) {
-      infof(data, "Sending quote commands\n");
-      sshc->quote_item = data->set.quote;
-      state(conn, SSH_SFTP_QUOTE);
-    }
-    else {
-      state(conn, SSH_SFTP_TRANS_INIT);
-    }
-    break;
 
-  case SSH_SFTP_POSTQUOTE_INIT:
-    if(data->set.postquote) {
-      infof(data, "Sending quote commands\n");
-      sshc->quote_item = data->set.postquote;
-      state(conn, SSH_SFTP_QUOTE);
-    }
-    else {
-      state(conn, SSH_STOP);
-    }
-    break;
-
-  case SSH_SFTP_QUOTE:
-    /* Send any quote commands */
-  {
-    const char *cp;
+    case SSH_SFTP_REALPATH:
+    {
+      char tempHome[PATH_MAX];
 
-    /*
-     * Support some of the "FTP" commands
-     */
-    if(curl_strequal("pwd", sshc->quote_item->data)) {
-      /* output debug output if that is requested */
-      if(data->set.verbose) {
-        char tmp[PATH_MAX+1];
-
-        Curl_debug(data, CURLINFO_HEADER_OUT, (char *)"PWD\n", 4, conn);
-        snprintf(tmp, PATH_MAX, "257 \"%s\" is current directory.\n",
-                 sftp_scp->path);
-        Curl_debug(data, CURLINFO_HEADER_IN, tmp, strlen(tmp), conn);
-      }
-      state(conn, SSH_SFTP_NEXT_QUOTE);
-      break;
-    }
-    else if(sshc->quote_item->data) {
       /*
-       * the arguments following the command must be separated from the
-       * command with a space so we can check for it unconditionally
+       * Get the "home" directory
        */
-      cp = strchr(sshc->quote_item->data, ' ');
-      if(cp == NULL) {
-        failf(data, "Syntax error in SFTP command. Supply parameter(s)!");
-        state(conn, SSH_SFTP_CLOSE);
-        sshc->actualcode = CURLE_QUOTE_ERROR;
+      rc = libssh2_sftp_realpath(sshc->sftp_session, ".",
+                                 tempHome, PATH_MAX-1);
+      if(rc == LIBSSH2_ERROR_EAGAIN) {
+        break;
+      }
+      else if(rc > 0) {
+        /* It seems that this string is not always NULL terminated */
+        tempHome[rc] = '\0';
+        sshc->homedir = strdup(tempHome);
+        if(!sshc->homedir) {
+          state(conn, SSH_SFTP_CLOSE);
+          sshc->actualcode = CURLE_OUT_OF_MEMORY;
+          break;
+        }
+      }
+      else {
+        /* Return the error type */
+        err = libssh2_sftp_last_error(sshc->sftp_session);
+        result = sftp_libssh2_error_to_CURLE(err);
+        sshc->actualcode = result?result:CURLE_SSH;
+        DEBUGF(infof(data, "error = %d makes libcurl = %d\n", err, result));
+        state(conn, SSH_STOP);
         break;
       }
+    }
+    /* This is the last step in the SFTP connect phase. Do note that while
+       we get the homedir here, we get the "workingpath" in the DO action
+       since the homedir will remain the same between request but the
+       working path will not. */
+    DEBUGF(infof(data, "SSH CONNECT phase done\n"));
+    state(conn, SSH_STOP);
+    break;
 
-      /*
-       * also, every command takes at least one argument so we get that
-       * first argument right now
-       */
-      result = get_pathname(&cp, &sshc->quote_path1);
+    case SSH_SFTP_QUOTE_INIT:
+
+      result = ssh_getworkingpath(conn, sshc->homedir, &sftp_scp->path);
       if(result) {
-        if(result == CURLE_OUT_OF_MEMORY)
-          failf(data, "Out of memory");
-        else
-          failf(data, "Syntax error: Bad first parameter");
-        state(conn, SSH_SFTP_CLOSE);
         sshc->actualcode = result;
+        state(conn, SSH_STOP);
         break;
       }
 
+      if(data->set.quote) {
+        infof(data, "Sending quote commands\n");
+        sshc->quote_item = data->set.quote;
+        state(conn, SSH_SFTP_QUOTE);
+      }
+      else {
+        state(conn, SSH_SFTP_TRANS_INIT);
+      }
+      break;
+
+    case SSH_SFTP_POSTQUOTE_INIT:
+      if(data->set.postquote) {
+        infof(data, "Sending quote commands\n");
+        sshc->quote_item = data->set.postquote;
+        state(conn, SSH_SFTP_QUOTE);
+      }
+      else {
+        state(conn, SSH_STOP);
+      }
+      break;
+
+    case SSH_SFTP_QUOTE:
+      /* Send any quote commands */
+    {
+      const char *cp;
+
       /*
-       * SFTP is a binary protocol, so we don't send text commands to
-       * the server. Instead, we scan for commands for commands used by
-       * OpenSSH's sftp program and call the appropriate libssh2
-       * functions.
+       * Support some of the "FTP" commands
        */
-      if(curl_strnequal(sshc->quote_item->data, "chgrp ", 6) ||
-         curl_strnequal(sshc->quote_item->data, "chmod ", 6) ||
-         curl_strnequal(sshc->quote_item->data, "chown ", 6) ) {
-        /* attribute change */
-
-        /* sshc->quote_path1 contains the mode to set */
-        /* get the destination */
-        result = get_pathname(&cp, &sshc->quote_path2);
+      if(curl_strequal("pwd", sshc->quote_item->data)) {
+        /* output debug output if that is requested */
+        if(data->set.verbose) {
+          char tmp[PATH_MAX+1];
+
+          Curl_debug(data, CURLINFO_HEADER_OUT, (char *)"PWD\n", 4, conn);
+          snprintf(tmp, PATH_MAX, "257 \"%s\" is current directory.\n",
+                   sftp_scp->path);
+          Curl_debug(data, CURLINFO_HEADER_IN, tmp, strlen(tmp), conn);
+        }
+        state(conn, SSH_SFTP_NEXT_QUOTE);
+        break;
+      }
+      else if(sshc->quote_item->data) {
+        /*
+         * the arguments following the command must be separated from the
+         * command with a space so we can check for it unconditionally
+         */
+        cp = strchr(sshc->quote_item->data, ' ');
+        if(cp == NULL) {
+          failf(data, "Syntax error in SFTP command. Supply parameter(s)!");
+          state(conn, SSH_SFTP_CLOSE);
+          sshc->actualcode = CURLE_QUOTE_ERROR;
+          break;
+        }
+
+        /*
+         * also, every command takes at least one argument so we get that
+         * first argument right now
+         */
+        result = get_pathname(&cp, &sshc->quote_path1);
         if(result) {
           if(result == CURLE_OUT_OF_MEMORY)
             failf(data, "Out of memory");
           else
-            failf(data, "Syntax error in chgrp/chmod/chown: "
-                  "Bad second parameter");
-          Curl_safefree(sshc->quote_path1);
-          sshc->quote_path1 = NULL;
+            failf(data, "Syntax error: Bad first parameter");
           state(conn, SSH_SFTP_CLOSE);
           sshc->actualcode = result;
           break;
         }
-        memset(&sshc->quote_attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES));
-        state(conn, SSH_SFTP_QUOTE_STAT);
+
+        /*
+         * SFTP is a binary protocol, so we don't send text commands to
+         * the server. Instead, we scan for commands for commands used by
+         * OpenSSH's sftp program and call the appropriate libssh2
+         * functions.
+         */
+        if(curl_strnequal(sshc->quote_item->data, "chgrp ", 6) ||
+           curl_strnequal(sshc->quote_item->data, "chmod ", 6) ||
+           curl_strnequal(sshc->quote_item->data, "chown ", 6) ) {
+          /* attribute change */
+
+          /* sshc->quote_path1 contains the mode to set */
+          /* get the destination */
+          result = get_pathname(&cp, &sshc->quote_path2);
+          if(result) {
+            if(result == CURLE_OUT_OF_MEMORY)
+              failf(data, "Out of memory");
+            else
+              failf(data, "Syntax error in chgrp/chmod/chown: "
+                    "Bad second parameter");
+            Curl_safefree(sshc->quote_path1);
+            sshc->quote_path1 = NULL;
+            state(conn, SSH_SFTP_CLOSE);
+            sshc->actualcode = result;
+            break;
+          }
+          memset(&sshc->quote_attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES));
+          state(conn, SSH_SFTP_QUOTE_STAT);
+          break;
+        }
+        else if(curl_strnequal(sshc->quote_item->data, "ln ", 3) ||
+                curl_strnequal(sshc->quote_item->data, "symlink ", 8)) {
+          /* symbolic linking */
+          /* sshc->quote_path1 is the source */
+          /* get the destination */
+          result = get_pathname(&cp, &sshc->quote_path2);
+          if(result) {
+            if(result == CURLE_OUT_OF_MEMORY)
+              failf(data, "Out of memory");
+            else
+              failf(data,
+                    "Syntax error in ln/symlink: Bad second parameter");
+            Curl_safefree(sshc->quote_path1);
+            sshc->quote_path1 = NULL;
+            state(conn, SSH_SFTP_CLOSE);
+            sshc->actualcode = result;
+            break;
+          }
+          state(conn, SSH_SFTP_QUOTE_SYMLINK);
+          break;
+        }
+        else if(curl_strnequal(sshc->quote_item->data, "mkdir ", 6)) {
+          /* create dir */
+          state(conn, SSH_SFTP_QUOTE_MKDIR);
+          break;
+        }
+        else if(curl_strnequal(sshc->quote_item->data, "rename ", 7)) {
+          /* rename file */
+          /* first param is the source path */
+          /* second param is the dest. path */
+          result = get_pathname(&cp, &sshc->quote_path2);
+          if(result) {
+            if(result == CURLE_OUT_OF_MEMORY)
+              failf(data, "Out of memory");
+            else
+              failf(data, "Syntax error in rename: Bad second parameter");
+            Curl_safefree(sshc->quote_path1);
+            sshc->quote_path1 = NULL;
+            state(conn, SSH_SFTP_CLOSE);
+            sshc->actualcode = result;
+            break;
+          }
+          state(conn, SSH_SFTP_QUOTE_RENAME);
+          break;
+        }
+        else if(curl_strnequal(sshc->quote_item->data, "rmdir ", 6)) {
+          /* delete dir */
+          state(conn, SSH_SFTP_QUOTE_RMDIR);
+          break;
+        }
+        else if(curl_strnequal(sshc->quote_item->data, "rm ", 3)) {
+          state(conn, SSH_SFTP_QUOTE_UNLINK);
+          break;
+        }
+
+        failf(data, "Unknown SFTP command");
+        Curl_safefree(sshc->quote_path1);
+        sshc->quote_path1 = NULL;
+        Curl_safefree(sshc->quote_path2);
+        sshc->quote_path2 = NULL;
+        state(conn, SSH_SFTP_CLOSE);
+        sshc->actualcode = CURLE_QUOTE_ERROR;
         break;
       }
-      else if(curl_strnequal(sshc->quote_item->data, "ln ", 3) ||
-              curl_strnequal(sshc->quote_item->data, "symlink ", 8)) {
-        /* symbolic linking */
-        /* sshc->quote_path1 is the source */
-        /* get the destination */
-        result = get_pathname(&cp, &sshc->quote_path2);
-        if(result) {
-          if(result == CURLE_OUT_OF_MEMORY)
-            failf(data, "Out of memory");
-          else
-            failf(data,
-                  "Syntax error in ln/symlink: Bad second parameter");
+    }
+    if(!sshc->quote_item) {
+      state(conn, SSH_SFTP_TRANS_INIT);
+    }
+    break;
+
+    case SSH_SFTP_NEXT_QUOTE:
+      if(sshc->quote_path1) {
+        Curl_safefree(sshc->quote_path1);
+        sshc->quote_path1 = NULL;
+      }
+      if(sshc->quote_path2) {
+        Curl_safefree(sshc->quote_path2);
+        sshc->quote_path2 = NULL;
+      }
+
+      sshc->quote_item = sshc->quote_item->next;
+
+      if(sshc->quote_item) {
+        state(conn, SSH_SFTP_QUOTE);
+      }
+      else {
+        if(sshc->nextstate != SSH_NO_STATE) {
+          state(conn, sshc->nextstate);
+          sshc->nextstate = SSH_NO_STATE;
+        }
+        else {
+          state(conn, SSH_SFTP_TRANS_INIT);
+        }
+      }
+      break;
+
+    case SSH_SFTP_QUOTE_STAT:
+      if(!curl_strnequal(sshc->quote_item->data, "chmod", 5)) {
+        /* Since chown and chgrp only set owner OR group but libssh2 wants to
+         * set them both at once, we need to obtain the current ownership first.
+         * This takes an extra protocol round trip.
+         */
+        rc = libssh2_sftp_stat(sshc->sftp_session, sshc->quote_path2,
+                               &sshc->quote_attrs);
+        if(rc == LIBSSH2_ERROR_EAGAIN) {
+          break;
+        }
+        else if(rc != 0) { /* get those attributes */
+          err = libssh2_sftp_last_error(sshc->sftp_session);
           Curl_safefree(sshc->quote_path1);
           sshc->quote_path1 = NULL;
+          Curl_safefree(sshc->quote_path2);
+          sshc->quote_path2 = NULL;
+          failf(data, "Attempt to get SFTP stats failed: %s",
+                sftp_libssh2_strerror(err));
           state(conn, SSH_SFTP_CLOSE);
-          sshc->actualcode = result;
+          sshc->actualcode = CURLE_QUOTE_ERROR;
           break;
         }
-        state(conn, SSH_SFTP_QUOTE_SYMLINK);
-        break;
       }
-      else if(curl_strnequal(sshc->quote_item->data, "mkdir ", 6)) {
-        /* create dir */
-        state(conn, SSH_SFTP_QUOTE_MKDIR);
-        break;
-      }
-      else if(curl_strnequal(sshc->quote_item->data, "rename ", 7)) {
-        /* rename file */
-        /* first param is the source path */
-        /* second param is the dest. path */
-        result = get_pathname(&cp, &sshc->quote_path2);
-        if(result) {
-          if(result == CURLE_OUT_OF_MEMORY)
-            failf(data, "Out of memory");
-          else
-            failf(data, "Syntax error in rename: Bad second parameter");
+
+      /* Now set the new attributes... */
+      if(curl_strnequal(sshc->quote_item->data, "chgrp", 5)) {
+        sshc->quote_attrs.gid = strtol(sshc->quote_path1, NULL, 10);
+        sshc->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID;
+        if(sshc->quote_attrs.gid == 0 && !ISDIGIT(sshc->quote_path1[0])) {
           Curl_safefree(sshc->quote_path1);
           sshc->quote_path1 = NULL;
+          Curl_safefree(sshc->quote_path2);
+          sshc->quote_path2 = NULL;
+          failf(data, "Syntax error: chgrp gid not a number");
           state(conn, SSH_SFTP_CLOSE);
-          sshc->actualcode = result;
+          sshc->actualcode = CURLE_QUOTE_ERROR;
           break;
         }
-        state(conn, SSH_SFTP_QUOTE_RENAME);
-        break;
       }
-      else if(curl_strnequal(sshc->quote_item->data, "rmdir ", 6)) {
-        /* delete dir */
-        state(conn, SSH_SFTP_QUOTE_RMDIR);
-        break;
+      else if(curl_strnequal(sshc->quote_item->data, "chmod", 5)) {
+        sshc->quote_attrs.permissions = strtol(sshc->quote_path1, NULL, 8);
+        sshc->quote_attrs.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS;
+        /* permissions are octal */
+        if(sshc->quote_attrs.permissions == 0 &&
+           !ISDIGIT(sshc->quote_path1[0])) {
+          Curl_safefree(sshc->quote_path1);
+          sshc->quote_path1 = NULL;
+          Curl_safefree(sshc->quote_path2);
+          sshc->quote_path2 = NULL;
+          failf(data, "Syntax error: chmod permissions not a number");
+          state(conn, SSH_SFTP_CLOSE);
+          sshc->actualcode = CURLE_QUOTE_ERROR;
+          break;
+        }
       }
-      else if(curl_strnequal(sshc->quote_item->data, "rm ", 3)) {
-        state(conn, SSH_SFTP_QUOTE_UNLINK);
-        break;
+      else if(curl_strnequal(sshc->quote_item->data, "chown", 5)) {
+        sshc->quote_attrs.uid = strtol(sshc->quote_path1, NULL, 10);
+        sshc->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID;
+        if(sshc->quote_attrs.uid == 0 && !ISDIGIT(sshc->quote_path1[0])) {
+          Curl_safefree(sshc->quote_path1);
+          sshc->quote_path1 = NULL;
+          Curl_safefree(sshc->quote_path2);
+          sshc->quote_path2 = NULL;
+          failf(data, "Syntax error: chown uid not a number");
+          state(conn, SSH_SFTP_CLOSE);
+          sshc->actualcode = CURLE_QUOTE_ERROR;
+          break;
+        }
       }
 
-      failf(data, "Unknown SFTP command");
-      Curl_safefree(sshc->quote_path1);
-      sshc->quote_path1 = NULL;
-      Curl_safefree(sshc->quote_path2);
-      sshc->quote_path2 = NULL;
-      state(conn, SSH_SFTP_CLOSE);
-      sshc->actualcode = CURLE_QUOTE_ERROR;
+      /* Now send the completed structure... */
+      state(conn, SSH_SFTP_QUOTE_SETSTAT);
       break;
-    }
-  }
-  if(!sshc->quote_item) {
-    state(conn, SSH_SFTP_TRANS_INIT);
-  }
-  break;
-
-  case SSH_SFTP_NEXT_QUOTE:
-    if(sshc->quote_path1) {
-      Curl_safefree(sshc->quote_path1);
-      sshc->quote_path1 = NULL;
-    }
-    if(sshc->quote_path2) {
-      Curl_safefree(sshc->quote_path2);
-      sshc->quote_path2 = NULL;
-    }
-
-    sshc->quote_item = sshc->quote_item->next;
-
-    if(sshc->quote_item) {
-      state(conn, SSH_SFTP_QUOTE);
-    }
-    else {
-      if(sshc->nextstate != SSH_NO_STATE) {
-        state(conn, sshc->nextstate);
-        sshc->nextstate = SSH_NO_STATE;
-      }
-      else {
-        state(conn, SSH_SFTP_TRANS_INIT);
-      }
-    }
-    break;
 
-  case SSH_SFTP_QUOTE_STAT:
-    if(!curl_strnequal(sshc->quote_item->data, "chmod", 5)) {
-      /* Since chown and chgrp only set owner OR group but libssh2 wants to
-       * set them both at once, we need to obtain the current ownership first.
-       * This takes an extra protocol round trip.
-       */
-      rc = libssh2_sftp_stat(sshc->sftp_session, sshc->quote_path2,
-                             &sshc->quote_attrs);
+    case SSH_SFTP_QUOTE_SETSTAT:
+      rc = libssh2_sftp_setstat(sshc->sftp_session, sshc->quote_path2,
+                                &sshc->quote_attrs);
       if(rc == LIBSSH2_ERROR_EAGAIN) {
         break;
       }
-      else if(rc != 0) { /* get those attributes */
+      else if(rc != 0) {
         err = libssh2_sftp_last_error(sshc->sftp_session);
         Curl_safefree(sshc->quote_path1);
         sshc->quote_path1 = NULL;
         Curl_safefree(sshc->quote_path2);
         sshc->quote_path2 = NULL;
-        failf(data, "Attempt to get SFTP stats failed: %s",
+        failf(data, "Attempt to set SFTP stats failed: %s",
               sftp_libssh2_strerror(err));
         state(conn, SSH_SFTP_CLOSE);
         sshc->actualcode = CURLE_QUOTE_ERROR;
         break;
       }
-    }
+      state(conn, SSH_SFTP_NEXT_QUOTE);
+      break;
 
-    /* Now set the new attributes... */
-    if(curl_strnequal(sshc->quote_item->data, "chgrp", 5)) {
-      sshc->quote_attrs.gid = strtol(sshc->quote_path1, NULL, 10);
-      sshc->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID;
-      if(sshc->quote_attrs.gid == 0 && !ISDIGIT(sshc->quote_path1[0])) {
+    case SSH_SFTP_QUOTE_SYMLINK:
+      rc = libssh2_sftp_symlink(sshc->sftp_session, sshc->quote_path1,
+                                sshc->quote_path2);
+      if(rc == LIBSSH2_ERROR_EAGAIN) {
+        break;
+      }
+      else if(rc != 0) {
+        err = libssh2_sftp_last_error(sshc->sftp_session);
         Curl_safefree(sshc->quote_path1);
         sshc->quote_path1 = NULL;
         Curl_safefree(sshc->quote_path2);
         sshc->quote_path2 = NULL;
-        failf(data, "Syntax error: chgrp gid not a number");
+        failf(data, "symlink command failed: %s",
+              sftp_libssh2_strerror(err));
         state(conn, SSH_SFTP_CLOSE);
         sshc->actualcode = CURLE_QUOTE_ERROR;
         break;
       }
-    }
-    else if(curl_strnequal(sshc->quote_item->data, "chmod", 5)) {
-      sshc->quote_attrs.permissions = strtol(sshc->quote_path1, NULL, 8);
-      sshc->quote_attrs.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS;
-      /* permissions are octal */
-      if(sshc->quote_attrs.permissions == 0 &&
-         !ISDIGIT(sshc->quote_path1[0])) {
+      state(conn, SSH_SFTP_NEXT_QUOTE);
+      break;
+
+    case SSH_SFTP_QUOTE_MKDIR:
+      rc = libssh2_sftp_mkdir(sshc->sftp_session, sshc->quote_path1, 0755);
+      if(rc == LIBSSH2_ERROR_EAGAIN) {
+        break;
+      }
+      else if(rc != 0) {
+        err = libssh2_sftp_last_error(sshc->sftp_session);
         Curl_safefree(sshc->quote_path1);
         sshc->quote_path1 = NULL;
-        Curl_safefree(sshc->quote_path2);
-        sshc->quote_path2 = NULL;
-        failf(data, "Syntax error: chmod permissions not a number");
+        failf(data, "mkdir command failed: %s", sftp_libssh2_strerror(err));
         state(conn, SSH_SFTP_CLOSE);
         sshc->actualcode = CURLE_QUOTE_ERROR;
         break;
       }
-    }
-    else if(curl_strnequal(sshc->quote_item->data, "chown", 5)) {
-      sshc->quote_attrs.uid = strtol(sshc->quote_path1, NULL, 10);
-      sshc->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID;
-      if(sshc->quote_attrs.uid == 0 && !ISDIGIT(sshc->quote_path1[0])) {
+      state(conn, SSH_SFTP_NEXT_QUOTE);
+      break;
+
+    case SSH_SFTP_QUOTE_RENAME:
+      rc = libssh2_sftp_rename(sshc->sftp_session, sshc->quote_path1,
+                               sshc->quote_path2);
+      if(rc == LIBSSH2_ERROR_EAGAIN) {
+        break;
+      }
+      else if(rc != 0) {
+        err = libssh2_sftp_last_error(sshc->sftp_session);
         Curl_safefree(sshc->quote_path1);
         sshc->quote_path1 = NULL;
         Curl_safefree(sshc->quote_path2);
         sshc->quote_path2 = NULL;
-        failf(data, "Syntax error: chown uid not a number");
+        failf(data, "rename command failed: %s", sftp_libssh2_strerror(err));
         state(conn, SSH_SFTP_CLOSE);
         sshc->actualcode = CURLE_QUOTE_ERROR;
         break;
       }
-    }
-
-    /* Now send the completed structure... */
-    state(conn, SSH_SFTP_QUOTE_SETSTAT);
-    break;
-
-  case SSH_SFTP_QUOTE_SETSTAT:
-    rc = libssh2_sftp_setstat(sshc->sftp_session, sshc->quote_path2,
-                              &sshc->quote_attrs);
-    if(rc == LIBSSH2_ERROR_EAGAIN) {
-      break;
-    }
-    else if(rc != 0) {
-      err = libssh2_sftp_last_error(sshc->sftp_session);
-      Curl_safefree(sshc->quote_path1);
-      sshc->quote_path1 = NULL;
-      Curl_safefree(sshc->quote_path2);
-      sshc->quote_path2 = NULL;
-      failf(data, "Attempt to set SFTP stats failed: %s",
-            sftp_libssh2_strerror(err));
-      state(conn, SSH_SFTP_CLOSE);
-      sshc->actualcode = CURLE_QUOTE_ERROR;
-      break;
-    }
-    state(conn, SSH_SFTP_NEXT_QUOTE);
-    break;
-
-  case SSH_SFTP_QUOTE_SYMLINK:
-    rc = libssh2_sftp_symlink(sshc->sftp_session, sshc->quote_path1,
-                              sshc->quote_path2);
-    if(rc == LIBSSH2_ERROR_EAGAIN) {
-      break;
-    }
-    else if(rc != 0) {
-      err = libssh2_sftp_last_error(sshc->sftp_session);
-      Curl_safefree(sshc->quote_path1);
-      sshc->quote_path1 = NULL;
-      Curl_safefree(sshc->quote_path2);
-      sshc->quote_path2 = NULL;
-      failf(data, "symlink command failed: %s",
-            sftp_libssh2_strerror(err));
-      state(conn, SSH_SFTP_CLOSE);
-      sshc->actualcode = CURLE_QUOTE_ERROR;
-      break;
-    }
-    state(conn, SSH_SFTP_NEXT_QUOTE);
-    break;
-
-  case SSH_SFTP_QUOTE_MKDIR:
-    rc = libssh2_sftp_mkdir(sshc->sftp_session, sshc->quote_path1, 0755);
-    if(rc == LIBSSH2_ERROR_EAGAIN) {
-      break;
-    }
-    else if(rc != 0) {
-      err = libssh2_sftp_last_error(sshc->sftp_session);
-      Curl_safefree(sshc->quote_path1);
-      sshc->quote_path1 = NULL;
-      failf(data, "mkdir command failed: %s", sftp_libssh2_strerror(err));
-      state(conn, SSH_SFTP_CLOSE);
-      sshc->actualcode = CURLE_QUOTE_ERROR;
+      state(conn, SSH_SFTP_NEXT_QUOTE);
       break;
-    }
-    state(conn, SSH_SFTP_NEXT_QUOTE);
-    break;
 
-  case SSH_SFTP_QUOTE_RENAME:
-    rc = libssh2_sftp_rename(sshc->sftp_session, sshc->quote_path1,
-                             sshc->quote_path2);
-    if(rc == LIBSSH2_ERROR_EAGAIN) {
-      break;
-    }
-    else if(rc != 0) {
-      err = libssh2_sftp_last_error(sshc->sftp_session);
-      Curl_safefree(sshc->quote_path1);
-      sshc->quote_path1 = NULL;
-      Curl_safefree(sshc->quote_path2);
-      sshc->quote_path2 = NULL;
-      failf(data, "rename command failed: %s", sftp_libssh2_strerror(err));
-      state(conn, SSH_SFTP_CLOSE);
-      sshc->actualcode = CURLE_QUOTE_ERROR;
+    case SSH_SFTP_QUOTE_RMDIR:
+      rc = libssh2_sftp_rmdir(sshc->sftp_session, sshc->quote_path1);
+      if(rc == LIBSSH2_ERROR_EAGAIN) {
+        break;
+      }
+      else if(rc != 0) {
+        err = libssh2_sftp_last_error(sshc->sftp_session);
+        Curl_safefree(sshc->quote_path1);
+        sshc->quote_path1 = NULL;
+        failf(data, "rmdir command failed: %s", sftp_libssh2_strerror(err));
+        state(conn, SSH_SFTP_CLOSE);
+        sshc->actualcode = CURLE_QUOTE_ERROR;
+        break;
+      }
+      state(conn, SSH_SFTP_NEXT_QUOTE);
       break;
-    }
-    state(conn, SSH_SFTP_NEXT_QUOTE);
-    break;
 
-  case SSH_SFTP_QUOTE_RMDIR:
-    rc = libssh2_sftp_rmdir(sshc->sftp_session, sshc->quote_path1);
-    if(rc == LIBSSH2_ERROR_EAGAIN) {
-      break;
-    }
-    else if(rc != 0) {
-      err = libssh2_sftp_last_error(sshc->sftp_session);
-      Curl_safefree(sshc->quote_path1);
-      sshc->quote_path1 = NULL;
-      failf(data, "rmdir command failed: %s", sftp_libssh2_strerror(err));
-      state(conn, SSH_SFTP_CLOSE);
-      sshc->actualcode = CURLE_QUOTE_ERROR;
+    case SSH_SFTP_QUOTE_UNLINK:
+      rc = libssh2_sftp_unlink(sshc->sftp_session, sshc->quote_path1);
+      if(rc == LIBSSH2_ERROR_EAGAIN) {
+        break;
+      }
+      else if(rc != 0) {
+        err = libssh2_sftp_last_error(sshc->sftp_session);
+        Curl_safefree(sshc->quote_path1);
+        sshc->quote_path1 = NULL;
+        failf(data, "rm command failed: %s", sftp_libssh2_strerror(err));
+        state(conn, SSH_SFTP_CLOSE);
+        sshc->actualcode = CURLE_QUOTE_ERROR;
+        break;
+      }
+      state(conn, SSH_SFTP_NEXT_QUOTE);
       break;
-    }
-    state(conn, SSH_SFTP_NEXT_QUOTE);
-    break;
 
-  case SSH_SFTP_QUOTE_UNLINK:
-    rc = libssh2_sftp_unlink(sshc->sftp_session, sshc->quote_path1);
-    if(rc == LIBSSH2_ERROR_EAGAIN) {
-      break;
-    }
-    else if(rc != 0) {
-      err = libssh2_sftp_last_error(sshc->sftp_session);
-      Curl_safefree(sshc->quote_path1);
-      sshc->quote_path1 = NULL;
-      failf(data, "rm command failed: %s", sftp_libssh2_strerror(err));
-      state(conn, SSH_SFTP_CLOSE);
-      sshc->actualcode = CURLE_QUOTE_ERROR;
+    case SSH_SFTP_TRANS_INIT:
+      if(data->set.upload)
+        state(conn, SSH_SFTP_UPLOAD_INIT);
+      else {
+        if(data->set.opt_no_body)
+          state(conn, SSH_STOP);
+        else if(sftp_scp->path[strlen(sftp_scp->path)-1] == '/')
+          state(conn, SSH_SFTP_READDIR_INIT);
+        else
+          state(conn, SSH_SFTP_DOWNLOAD_INIT);
+      }
       break;
-    }
-    state(conn, SSH_SFTP_NEXT_QUOTE);
-    break;
 
-  case SSH_SFTP_TRANS_INIT:
-    if(data->set.upload)
-      state(conn, SSH_SFTP_UPLOAD_INIT);
-    else {
-      if(data->set.opt_no_body)
-        state(conn, SSH_STOP);
-      else if(sftp_scp->path[strlen(sftp_scp->path)-1] == '/')
-        state(conn, SSH_SFTP_READDIR_INIT);
-      else
-        state(conn, SSH_SFTP_DOWNLOAD_INIT);
-    }
-    break;
+    case SSH_SFTP_UPLOAD_INIT:
+    {
+      unsigned long flags;
+      /*
+       * NOTE!!!  libssh2 requires that the destination path is a full path
+       *          that includes the destination file and name OR ends in a "/"
+       *          If this is not done the destination file will be named the
+       *          same name as the last directory in the path.
+       */
 
-  case SSH_SFTP_UPLOAD_INIT:
-  {
-    unsigned long flags;
-    /*
-     * NOTE!!!  libssh2 requires that the destination path is a full path
-     *          that includes the destination file and name OR ends in a "/"
-     *          If this is not done the destination file will be named the
-     *          same name as the last directory in the path.
-     */
-
-    if(data->state.resume_from != 0) {
-      LIBSSH2_SFTP_ATTRIBUTES attrs;
-      if(data->state.resume_from< 0) {
-        rc = libssh2_sftp_stat(sshc->sftp_session, sftp_scp->path, &attrs);
-        if(rc == LIBSSH2_ERROR_EAGAIN) {
-          break;
-        }
-        else if(rc) {
-          data->state.resume_from = 0;
-        }
-        else {
-          data->state.resume_from = attrs.filesize;
+      if(data->state.resume_from != 0) {
+        LIBSSH2_SFTP_ATTRIBUTES attrs;
+        if(data->state.resume_from< 0) {
+          rc = libssh2_sftp_stat(sshc->sftp_session, sftp_scp->path, &attrs);
+          if(rc == LIBSSH2_ERROR_EAGAIN) {
+            break;
+          }
+          else if(rc) {
+            data->state.resume_from = 0;
+          }
+          else {
+            data->state.resume_from = attrs.filesize;
+          }
         }
       }
-    }
 
-    if(data->set.ftp_append)
-      /* Try to open for append, but create if nonexisting */
-      flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_APPEND;
-    else if (data->state.resume_from > 0)
-      /* If we have restart position then open for append */
-      flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_APPEND;
-    else
-      /* Clear file before writing (normal behaviour) */
-      flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC;
+      if(data->set.ftp_append)
+        /* Try to open for append, but create if nonexisting */
+        flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_APPEND;
+      else if (data->state.resume_from > 0)
+        /* If we have restart position then open for append */
+        flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_APPEND;
+      else
+        /* Clear file before writing (normal behaviour) */
+        flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC;
 
-    sshc->sftp_handle =
-      libssh2_sftp_open(sshc->sftp_session, sftp_scp->path,
-                        flags, data->set.new_file_perms);
+      sshc->sftp_handle =
+        libssh2_sftp_open(sshc->sftp_session, sftp_scp->path,
+                          flags, data->set.new_file_perms);
 
-    if(!sshc->sftp_handle) {
-      rc = libssh2_session_last_errno(sshc->ssh_session);
+      if(!sshc->sftp_handle) {
+        rc = libssh2_session_last_errno(sshc->ssh_session);
 
-      if(LIBSSH2_ERROR_EAGAIN == rc)
-        break;
-      else {
-        if(LIBSSH2_ERROR_SFTP_PROTOCOL == rc)
-          /* only when there was an SFTP protocol error can we extract
-             the sftp error! */
-          err = libssh2_sftp_last_error(sshc->sftp_session);
-        else
-          err = -1; /* not an sftp error at all */
+        if(LIBSSH2_ERROR_EAGAIN == rc)
+          break;
+        else {
+          if(LIBSSH2_ERROR_SFTP_PROTOCOL == rc)
+            /* only when there was an SFTP protocol error can we extract
+               the sftp error! */
+            err = libssh2_sftp_last_error(sshc->sftp_session);
+          else
+            err = -1; /* not an sftp error at all */
 
-        if(sshc->secondCreateDirs) {
+          if(sshc->secondCreateDirs) {
+            state(conn, SSH_SFTP_CLOSE);
+            sshc->actualcode = err>= LIBSSH2_FX_OK?
+              sftp_libssh2_error_to_CURLE(err):CURLE_SSH;
+            failf(data, "Creating the dir/file failed: %s",
+                  sftp_libssh2_strerror(err));
+            break;
+          }
+          else if(((err == LIBSSH2_FX_NO_SUCH_FILE) ||
+                   (err == LIBSSH2_FX_FAILURE) ||
+                   (err == LIBSSH2_FX_NO_SUCH_PATH)) &&
+                  (data->set.ftp_create_missing_dirs &&
+                   (strlen(sftp_scp->path) > 1))) {
+            /* try to create the path remotely */
+            sshc->secondCreateDirs = 1;
+            state(conn, SSH_SFTP_CREATE_DIRS_INIT);
+            break;
+          }
           state(conn, SSH_SFTP_CLOSE);
           sshc->actualcode = err>= LIBSSH2_FX_OK?
             sftp_libssh2_error_to_CURLE(err):CURLE_SSH;
-          failf(data, "Creating the dir/file failed: %s",
-                sftp_libssh2_strerror(err));
-          break;
-        }
-        else if(((err == LIBSSH2_FX_NO_SUCH_FILE) ||
-                 (err == LIBSSH2_FX_FAILURE) ||
-                 (err == LIBSSH2_FX_NO_SUCH_PATH)) &&
-                (data->set.ftp_create_missing_dirs &&
-                 (strlen(sftp_scp->path) > 1))) {
-          /* try to create the path remotely */
-          sshc->secondCreateDirs = 1;
-          state(conn, SSH_SFTP_CREATE_DIRS_INIT);
+          if(!sshc->actualcode) {
+            /* Sometimes, for some reason libssh2_sftp_last_error() returns
+               zero even though libssh2_sftp_open() failed previously! We need
+               to work around that! */
+            sshc->actualcode = CURLE_SSH;
+            err=-1;
+          }
+          failf(data, "Upload failed: %s (%d/%d)",
+                err>= LIBSSH2_FX_OK?sftp_libssh2_strerror(err):"ssh error",
+                err, rc);
           break;
         }
-        state(conn, SSH_SFTP_CLOSE);
-        sshc->actualcode = err>= LIBSSH2_FX_OK?
-          sftp_libssh2_error_to_CURLE(err):CURLE_SSH;
-        if(!sshc->actualcode) {
-          /* Sometimes, for some reason libssh2_sftp_last_error() returns zero
-             even though libssh2_sftp_open() failed previously! We need to
-             work around that! */
-          sshc->actualcode = CURLE_SSH;
-          err=-1;
-        }
-        failf(data, "Upload failed: %s (%d/%d)",
-              err>= LIBSSH2_FX_OK?sftp_libssh2_strerror(err):"ssh error",
-              err, rc);
-        break;
       }
-    }
 
-    /* If we have restart point then we need to seek to the correct position. */
-    if(data->state.resume_from > 0) {
-      /* Let's read off the proper amount of bytes from the input. */
-      if(conn->seek_func) {
-        seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
-                                  SEEK_SET);
-      }
+      /* If we have restart point then we need to seek to the correct
+         position. */
+      if(data->state.resume_from > 0) {
+        /* Let's read off the proper amount of bytes from the input. */
+        if(conn->seek_func) {
+          seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
+                                    SEEK_SET);
+        }
 
-      if(seekerr != CURL_SEEKFUNC_OK){
+        if(seekerr != CURL_SEEKFUNC_OK){
 
-        if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
-          failf(data, "Could not seek stream");
-          return CURLE_FTP_COULDNT_USE_REST;
+          if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
+            failf(data, "Could not seek stream");
+            return CURLE_FTP_COULDNT_USE_REST;
+          }
+          /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
+          else {
+            curl_off_t passed=0;
+            curl_off_t readthisamountnow;
+            curl_off_t actuallyread;
+            do {
+              readthisamountnow = (data->state.resume_from - passed);
+
+              if(readthisamountnow > BUFSIZE)
+                readthisamountnow = BUFSIZE;
+
+              actuallyread =
+                (curl_off_t) conn->fread_func(data->state.buffer, 1,
+                                              (size_t)readthisamountnow,
+                                              conn->fread_in);
+
+              passed += actuallyread;
+              if((actuallyread <= 0) || (actuallyread > readthisamountnow)) {
+                /* this checks for greater-than only to make sure that the
+                   CURL_READFUNC_ABORT return code still aborts */
+                failf(data, "Failed to read data");
+                return CURLE_FTP_COULDNT_USE_REST;
+              }
+            } while(passed < data->state.resume_from);
+          }
         }
-        /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
-        else {
-          curl_off_t passed=0;
-          curl_off_t readthisamountnow;
-          curl_off_t actuallyread;
-          do {
-            readthisamountnow = (data->state.resume_from - passed);
-
-            if(readthisamountnow > BUFSIZE)
-              readthisamountnow = BUFSIZE;
-
-            actuallyread =
-              (curl_off_t) conn->fread_func(data->state.buffer, 1,
-                                            (size_t)readthisamountnow,
-                                            conn->fread_in);
-
-            passed += actuallyread;
-            if((actuallyread <= 0) || (actuallyread > readthisamountnow)) {
-              /* this checks for greater-than only to make sure that the
-                 CURL_READFUNC_ABORT return code still aborts */
-              failf(data, "Failed to read data");
-              return CURLE_FTP_COULDNT_USE_REST;
-            }
-          } while(passed < data->state.resume_from);
+
+        /* now, decrease the size of the read */
+        if(data->set.infilesize>0) {
+          data->set.infilesize -= data->state.resume_from;
+          data->req.size = data->set.infilesize;
+          Curl_pgrsSetUploadSize(data, data->set.infilesize);
         }
-      }
 
-      /* now, decrease the size of the read */
+        SFTP_SEEK(sshc->sftp_handle, data->state.resume_from);
+      }
       if(data->set.infilesize>0) {
-        data->set.infilesize -= data->state.resume_from;
         data->req.size = data->set.infilesize;
         Curl_pgrsSetUploadSize(data, data->set.infilesize);
       }
+      /* upload data */
+      result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL,
+                                   FIRSTSOCKET, NULL);
 
-      SFTP_SEEK(sshc->sftp_handle, data->state.resume_from);
-    }
-    if(data->set.infilesize>0) {
-      data->req.size = data->set.infilesize;
-      Curl_pgrsSetUploadSize(data, data->set.infilesize);
-    }
-    /* upload data */
-    result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL,
-                                 FIRSTSOCKET, NULL);
-
-    /* not set by Curl_setup_transfer to preserve keepon bits */
-    conn->sockfd = conn->writesockfd;
+      /* not set by Curl_setup_transfer to preserve keepon bits */
+      conn->sockfd = conn->writesockfd;
 
-    if(result) {
-      state(conn, SSH_SFTP_CLOSE);
-      sshc->actualcode = result;
-    }
-    else {
-      /* store this original bitmask setup to use later on if we can't figure
-         out a "real" bitmask */
-      sshc->orig_waitfor = data->req.keepon;
-
-      state(conn, SSH_STOP);
-    }
-    break;
-  }
-
-  case SSH_SFTP_CREATE_DIRS_INIT:
-    if(strlen(sftp_scp->path) > 1) {
-      sshc->slash_pos = sftp_scp->path + 1; /* ignore the leading '/' */
-      state(conn, SSH_SFTP_CREATE_DIRS);
-    }
-    else {
-      state(conn, SSH_SFTP_UPLOAD_INIT);
-    }
-    break;
-
-  case SSH_SFTP_CREATE_DIRS:
-    if((sshc->slash_pos = strchr(sshc->slash_pos, '/')) != NULL) {
-      *sshc->slash_pos = 0;
+      if(result) {
+        state(conn, SSH_SFTP_CLOSE);
+        sshc->actualcode = result;
+      }
+      else {
+        /* store this original bitmask setup to use later on if we can't
+           figure out a "real" bitmask */
+        sshc->orig_waitfor = data->req.keepon;
 
-      infof(data, "Creating directory '%s'\n", sftp_scp->path);
-      state(conn, SSH_SFTP_CREATE_DIRS_MKDIR);
+        state(conn, SSH_STOP);
+      }
       break;
     }
-    else {
-      state(conn, SSH_SFTP_UPLOAD_INIT);
-    }
-    break;
 
-  case SSH_SFTP_CREATE_DIRS_MKDIR:
-    /* 'mode' - parameter is preliminary - default to 0644 */
-    rc = libssh2_sftp_mkdir(sshc->sftp_session, sftp_scp->path,
-                            data->set.new_directory_perms);
-    if(rc == LIBSSH2_ERROR_EAGAIN) {
-      break;
-    }
-    *sshc->slash_pos = '/';
-    ++sshc->slash_pos;
-    if(rc == -1) {
-      unsigned int sftp_err = 0;
-      /*
-       * abort if failure wasn't that the dir already exists or the
-       * permission was denied (creation might succeed further
-       * down the path) - retry on unspecific FAILURE also
-       */
-      sftp_err = libssh2_sftp_last_error(sshc->sftp_session);
-      if((sftp_err != LIBSSH2_FX_FILE_ALREADY_EXISTS) &&
-         (sftp_err != LIBSSH2_FX_FAILURE) &&
-         (sftp_err != LIBSSH2_FX_PERMISSION_DENIED)) {
-        result = sftp_libssh2_error_to_CURLE(sftp_err);
-        state(conn, SSH_SFTP_CLOSE);
-        sshc->actualcode = result?result:CURLE_SSH;
-        break;
+    case SSH_SFTP_CREATE_DIRS_INIT:
+      if(strlen(sftp_scp->path) > 1) {
+        sshc->slash_pos = sftp_scp->path + 1; /* ignore the leading '/' */
+        state(conn, SSH_SFTP_CREATE_DIRS);
       }
-    }
-    state(conn, SSH_SFTP_CREATE_DIRS);
-    break;
+      else {
+        state(conn, SSH_SFTP_UPLOAD_INIT);
+      }
+      break;
 
-  case SSH_SFTP_READDIR_INIT:
-    /*
-     * This is a directory that we are trying to get, so produce a
-     * directory listing
-     */
-    sshc->sftp_handle = libssh2_sftp_opendir(sshc->sftp_session,
-                                             sftp_scp->path);
-    if(!sshc->sftp_handle) {
-      if(libssh2_session_last_errno(sshc->ssh_session) ==
-         LIBSSH2_ERROR_EAGAIN) {
-        rc = LIBSSH2_ERROR_EAGAIN;
+    case SSH_SFTP_CREATE_DIRS:
+      if((sshc->slash_pos = strchr(sshc->slash_pos, '/')) != NULL) {
+        *sshc->slash_pos = 0;
+
+        infof(data, "Creating directory '%s'\n", sftp_scp->path);
+        state(conn, SSH_SFTP_CREATE_DIRS_MKDIR);
         break;
       }
       else {
-        err = libssh2_sftp_last_error(sshc->sftp_session);
-        failf(data, "Could not open directory for reading: %s",
-              sftp_libssh2_strerror(err));
-        state(conn, SSH_SFTP_CLOSE);
-        result = sftp_libssh2_error_to_CURLE(err);
-        sshc->actualcode = result?result:CURLE_SSH;
-        break;
+        state(conn, SSH_SFTP_UPLOAD_INIT);
       }
-    }
-    if((sshc->readdir_filename = malloc(PATH_MAX+1)) == NULL) {
-      state(conn, SSH_SFTP_CLOSE);
-      sshc->actualcode = CURLE_OUT_OF_MEMORY;
       break;
-    }
-    if((sshc->readdir_longentry = malloc(PATH_MAX+1)) == NULL) {
-      Curl_safefree(sshc->readdir_filename);
-      sshc->readdir_filename = NULL;
-      state(conn, SSH_SFTP_CLOSE);
-      sshc->actualcode = CURLE_OUT_OF_MEMORY;
-      break;
-    }
-    state(conn, SSH_SFTP_READDIR);
-    break;
-
-  case SSH_SFTP_READDIR:
-    sshc->readdir_len = libssh2_sftp_readdir_ex(sshc->sftp_handle,
-                                                sshc->readdir_filename,
-                                                PATH_MAX,
-                                                sshc->readdir_longentry,
-                                                PATH_MAX,
-                                                &sshc->readdir_attrs);
-    if(sshc->readdir_len == LIBSSH2_ERROR_EAGAIN) {
-      rc = LIBSSH2_ERROR_EAGAIN;
-      break;
-    }
-    if(sshc->readdir_len > 0) {
-      sshc->readdir_filename[sshc->readdir_len] = '\0';
-
-      if(data->set.ftp_list_only) {
-        char *tmpLine;
 
-        tmpLine = aprintf("%s\n", sshc->readdir_filename);
-        if(tmpLine == NULL) {
+    case SSH_SFTP_CREATE_DIRS_MKDIR:
+      /* 'mode' - parameter is preliminary - default to 0644 */
+      rc = libssh2_sftp_mkdir(sshc->sftp_session, sftp_scp->path,
+                              data->set.new_directory_perms);
+      if(rc == LIBSSH2_ERROR_EAGAIN) {
+        break;
+      }
+      *sshc->slash_pos = '/';
+      ++sshc->slash_pos;
+      if(rc == -1) {
+        unsigned int sftp_err = 0;
+        /*
+         * Abort if failure wasn't that the dir already exists or the
+         * permission was denied (creation might succeed further down the
+         * path) - retry on unspecific FAILURE also
+         */
+        sftp_err = libssh2_sftp_last_error(sshc->sftp_session);
+        if((sftp_err != LIBSSH2_FX_FILE_ALREADY_EXISTS) &&
+           (sftp_err != LIBSSH2_FX_FAILURE) &&
+           (sftp_err != LIBSSH2_FX_PERMISSION_DENIED)) {
+          result = sftp_libssh2_error_to_CURLE(sftp_err);
           state(conn, SSH_SFTP_CLOSE);
-          sshc->actualcode = CURLE_OUT_OF_MEMORY;
+          sshc->actualcode = result?result:CURLE_SSH;
           break;
         }
-        result = Curl_client_write(conn, CLIENTWRITE_BODY,
-                                   tmpLine, sshc->readdir_len+1);
-        Curl_safefree(tmpLine);
+      }
+      state(conn, SSH_SFTP_CREATE_DIRS);
+      break;
 
-        if(result) {
-          state(conn, SSH_STOP);
+    case SSH_SFTP_READDIR_INIT:
+      /*
+       * This is a directory that we are trying to get, so produce a directory
+       * listing
+       */
+      sshc->sftp_handle = libssh2_sftp_opendir(sshc->sftp_session,
+                                               sftp_scp->path);
+      if(!sshc->sftp_handle) {
+        if(libssh2_session_last_errno(sshc->ssh_session) ==
+           LIBSSH2_ERROR_EAGAIN) {
+          rc = LIBSSH2_ERROR_EAGAIN;
           break;
         }
-        /* since this counts what we send to the client, we include the newline
-           in this counter */
-        data->req.bytecount += sshc->readdir_len+1;
-
-        /* output debug output if that is requested */
-        if(data->set.verbose) {
-          Curl_debug(data, CURLINFO_DATA_OUT, sshc->readdir_filename,
-                     sshc->readdir_len, conn);
-        }
-      }
-      else {
-        sshc->readdir_currLen = strlen(sshc->readdir_longentry);
-        sshc->readdir_totalLen = 80 + sshc->readdir_currLen;
-        sshc->readdir_line = calloc(sshc->readdir_totalLen, 1);
-        if(!sshc->readdir_line) {
-          Curl_safefree(sshc->readdir_filename);
-          sshc->readdir_filename = NULL;
-          Curl_safefree(sshc->readdir_longentry);
-          sshc->readdir_longentry = NULL;
+        else {
+          err = libssh2_sftp_last_error(sshc->sftp_session);
+          failf(data, "Could not open directory for reading: %s",
+                sftp_libssh2_strerror(err));
           state(conn, SSH_SFTP_CLOSE);
-          sshc->actualcode = CURLE_OUT_OF_MEMORY;
+          result = sftp_libssh2_error_to_CURLE(err);
+          sshc->actualcode = result?result:CURLE_SSH;
           break;
         }
+      }
+      if((sshc->readdir_filename = malloc(PATH_MAX+1)) == NULL) {
+        state(conn, SSH_SFTP_CLOSE);
+        sshc->actualcode = CURLE_OUT_OF_MEMORY;
+        break;
+      }
+      if((sshc->readdir_longentry = malloc(PATH_MAX+1)) == NULL) {
+        Curl_safefree(sshc->readdir_filename);
+        sshc->readdir_filename = NULL;
+        state(conn, SSH_SFTP_CLOSE);
+        sshc->actualcode = CURLE_OUT_OF_MEMORY;
+        break;
+      }
+      state(conn, SSH_SFTP_READDIR);
+      break;
+
+    case SSH_SFTP_READDIR:
+      sshc->readdir_len = libssh2_sftp_readdir_ex(sshc->sftp_handle,
+                                                  sshc->readdir_filename,
+                                                  PATH_MAX,
+                                                  sshc->readdir_longentry,
+                                                  PATH_MAX,
+                                                  &sshc->readdir_attrs);
+      if(sshc->readdir_len == LIBSSH2_ERROR_EAGAIN) {
+        rc = LIBSSH2_ERROR_EAGAIN;
+        break;
+      }
+      if(sshc->readdir_len > 0) {
+        sshc->readdir_filename[sshc->readdir_len] = '\0';
 
-        memcpy(sshc->readdir_line, sshc->readdir_longentry,
-               sshc->readdir_currLen);
-        if((sshc->readdir_attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) &&
-           ((sshc->readdir_attrs.permissions & LIBSSH2_SFTP_S_IFMT) ==
-            LIBSSH2_SFTP_S_IFLNK)) {
-          sshc->readdir_linkPath = malloc(PATH_MAX + 1);
-          if(sshc->readdir_linkPath == NULL) {
+        if(data->set.ftp_list_only) {
+          char *tmpLine;
+
+          tmpLine = aprintf("%s\n", sshc->readdir_filename);
+          if(tmpLine == NULL) {
+            state(conn, SSH_SFTP_CLOSE);
+            sshc->actualcode = CURLE_OUT_OF_MEMORY;
+            break;
+          }
+          result = Curl_client_write(conn, CLIENTWRITE_BODY,
+                                     tmpLine, sshc->readdir_len+1);
+          Curl_safefree(tmpLine);
+
+          if(result) {
+            state(conn, SSH_STOP);
+            break;
+          }
+          /* since this counts what we send to the client, we include the
+             newline in this counter */
+          data->req.bytecount += sshc->readdir_len+1;
+
+          /* output debug output if that is requested */
+          if(data->set.verbose) {
+            Curl_debug(data, CURLINFO_DATA_OUT, sshc->readdir_filename,
+                       sshc->readdir_len, conn);
+          }
+        }
+        else {
+          sshc->readdir_currLen = strlen(sshc->readdir_longentry);
+          sshc->readdir_totalLen = 80 + sshc->readdir_currLen;
+          sshc->readdir_line = calloc(sshc->readdir_totalLen, 1);
+          if(!sshc->readdir_line) {
             Curl_safefree(sshc->readdir_filename);
             sshc->readdir_filename = NULL;
             Curl_safefree(sshc->readdir_longentry);
@@ -1678,563 +1665,581 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
             break;
           }
 
-          snprintf(sshc->readdir_linkPath, PATH_MAX, "%s%s", sftp_scp->path,
-                   sshc->readdir_filename);
-          state(conn, SSH_SFTP_READDIR_LINK);
+          memcpy(sshc->readdir_line, sshc->readdir_longentry,
+                 sshc->readdir_currLen);
+          if((sshc->readdir_attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) &&
+             ((sshc->readdir_attrs.permissions & LIBSSH2_SFTP_S_IFMT) ==
+              LIBSSH2_SFTP_S_IFLNK)) {
+            sshc->readdir_linkPath = malloc(PATH_MAX + 1);
+            if(sshc->readdir_linkPath == NULL) {
+              Curl_safefree(sshc->readdir_filename);
+              sshc->readdir_filename = NULL;
+              Curl_safefree(sshc->readdir_longentry);
+              sshc->readdir_longentry = NULL;
+              state(conn, SSH_SFTP_CLOSE);
+              sshc->actualcode = CURLE_OUT_OF_MEMORY;
+              break;
+            }
+
+            snprintf(sshc->readdir_linkPath, PATH_MAX, "%s%s", sftp_scp->path,
+                     sshc->readdir_filename);
+            state(conn, SSH_SFTP_READDIR_LINK);
+            break;
+          }
+          state(conn, SSH_SFTP_READDIR_BOTTOM);
           break;
         }
-        state(conn, SSH_SFTP_READDIR_BOTTOM);
+      }
+      else if(sshc->readdir_len == 0) {
+        Curl_safefree(sshc->readdir_filename);
+        sshc->readdir_filename = NULL;
+        Curl_safefree(sshc->readdir_longentry);
+        sshc->readdir_longentry = NULL;
+        state(conn, SSH_SFTP_READDIR_DONE);
+        break;
+      }
+      else if(sshc->readdir_len <= 0) {
+        err = libssh2_sftp_last_error(sshc->sftp_session);
+        result = sftp_libssh2_error_to_CURLE(err);
+        sshc->actualcode = result?result:CURLE_SSH;
+        failf(data, "Could not open remote file for reading: %s :: %d",
+              sftp_libssh2_strerror(err),
+              libssh2_session_last_errno(sshc->ssh_session));
+        Curl_safefree(sshc->readdir_filename);
+        sshc->readdir_filename = NULL;
+        Curl_safefree(sshc->readdir_longentry);
+        sshc->readdir_longentry = NULL;
+        state(conn, SSH_SFTP_CLOSE);
         break;
       }
-    }
-    else if(sshc->readdir_len == 0) {
-      Curl_safefree(sshc->readdir_filename);
-      sshc->readdir_filename = NULL;
-      Curl_safefree(sshc->readdir_longentry);
-      sshc->readdir_longentry = NULL;
-      state(conn, SSH_SFTP_READDIR_DONE);
-      break;
-    }
-    else if(sshc->readdir_len <= 0) {
-      err = libssh2_sftp_last_error(sshc->sftp_session);
-      result = sftp_libssh2_error_to_CURLE(err);
-      sshc->actualcode = result?result:CURLE_SSH;
-      failf(data, "Could not open remote file for reading: %s :: %d",
-            sftp_libssh2_strerror(err),
-            libssh2_session_last_errno(sshc->ssh_session));
-      Curl_safefree(sshc->readdir_filename);
-      sshc->readdir_filename = NULL;
-      Curl_safefree(sshc->readdir_longentry);
-      sshc->readdir_longentry = NULL;
-      state(conn, SSH_SFTP_CLOSE);
       break;
-    }
-    break;
 
-  case SSH_SFTP_READDIR_LINK:
-    sshc->readdir_len = libssh2_sftp_readlink(sshc->sftp_session,
-                                              sshc->readdir_linkPath,
-                                              sshc->readdir_filename,
-                                              PATH_MAX);
-    if(sshc->readdir_len == LIBSSH2_ERROR_EAGAIN) {
-      rc = LIBSSH2_ERROR_EAGAIN;
-      break;
-    }
-    Curl_safefree(sshc->readdir_linkPath);
-    sshc->readdir_linkPath = NULL;
-    sshc->readdir_line = realloc(sshc->readdir_line,
-                                 sshc->readdir_totalLen + 4 +
-                                 sshc->readdir_len);
-    if(!sshc->readdir_line) {
-      Curl_safefree(sshc->readdir_filename);
-      sshc->readdir_filename = NULL;
-      Curl_safefree(sshc->readdir_longentry);
-      sshc->readdir_longentry = NULL;
-      state(conn, SSH_SFTP_CLOSE);
-      sshc->actualcode = CURLE_OUT_OF_MEMORY;
-      break;
-    }
+    case SSH_SFTP_READDIR_LINK:
+      sshc->readdir_len = libssh2_sftp_readlink(sshc->sftp_session,
+                                                sshc->readdir_linkPath,
+                                                sshc->readdir_filename,
+                                                PATH_MAX);
+      if(sshc->readdir_len == LIBSSH2_ERROR_EAGAIN) {
+        rc = LIBSSH2_ERROR_EAGAIN;
+        break;
+      }
+      Curl_safefree(sshc->readdir_linkPath);
+      sshc->readdir_linkPath = NULL;
+      sshc->readdir_line = realloc(sshc->readdir_line,
+                                   sshc->readdir_totalLen + 4 +
+                                   sshc->readdir_len);
+      if(!sshc->readdir_line) {
+        Curl_safefree(sshc->readdir_filename);
+        sshc->readdir_filename = NULL;
+        Curl_safefree(sshc->readdir_longentry);
+        sshc->readdir_longentry = NULL;
+        state(conn, SSH_SFTP_CLOSE);
+        sshc->actualcode = CURLE_OUT_OF_MEMORY;
+        break;
+      }
 
-    sshc->readdir_currLen += snprintf(sshc->readdir_line +
-                                      sshc->readdir_currLen,
-                                      sshc->readdir_totalLen -
-                                      sshc->readdir_currLen,
-                                      " -> %s",
-                                      sshc->readdir_filename);
+      sshc->readdir_currLen += snprintf(sshc->readdir_line +
+                                        sshc->readdir_currLen,
+                                        sshc->readdir_totalLen -
+                                        sshc->readdir_currLen,
+                                        " -> %s",
+                                        sshc->readdir_filename);
 
-    state(conn, SSH_SFTP_READDIR_BOTTOM);
-    break;
+      state(conn, SSH_SFTP_READDIR_BOTTOM);
+      break;
 
-  case SSH_SFTP_READDIR_BOTTOM:
-    sshc->readdir_currLen += snprintf(sshc->readdir_line +
-                                      sshc->readdir_currLen,
-                                      sshc->readdir_totalLen -
-                                      sshc->readdir_currLen, "\n");
-    result = Curl_client_write(conn, CLIENTWRITE_BODY,
-                               sshc->readdir_line,
-                               sshc->readdir_currLen);
+    case SSH_SFTP_READDIR_BOTTOM:
+      sshc->readdir_currLen += snprintf(sshc->readdir_line +
+                                        sshc->readdir_currLen,
+                                        sshc->readdir_totalLen -
+                                        sshc->readdir_currLen, "\n");
+      result = Curl_client_write(conn, CLIENTWRITE_BODY,
+                                 sshc->readdir_line,
+                                 sshc->readdir_currLen);
 
-    if(result == CURLE_OK) {
+      if(result == CURLE_OK) {
 
-      /* output debug output if that is requested */
-      if(data->set.verbose) {
-        Curl_debug(data, CURLINFO_DATA_OUT, sshc->readdir_line,
-                   sshc->readdir_currLen, conn);
+        /* output debug output if that is requested */
+        if(data->set.verbose) {
+          Curl_debug(data, CURLINFO_DATA_OUT, sshc->readdir_line,
+                     sshc->readdir_currLen, conn);
+        }
+        data->req.bytecount += sshc->readdir_currLen;
       }
-      data->req.bytecount += sshc->readdir_currLen;
-    }
-    Curl_safefree(sshc->readdir_line);
-    sshc->readdir_line = NULL;
-    if(result) {
-      state(conn, SSH_STOP);
-    }
-    else
-      state(conn, SSH_SFTP_READDIR);
-    break;
-
-  case SSH_SFTP_READDIR_DONE:
-    if(libssh2_sftp_closedir(sshc->sftp_handle) ==
-       LIBSSH2_ERROR_EAGAIN) {
-      rc = LIBSSH2_ERROR_EAGAIN;
+      Curl_safefree(sshc->readdir_line);
+      sshc->readdir_line = NULL;
+      if(result) {
+        state(conn, SSH_STOP);
+      }
+      else
+        state(conn, SSH_SFTP_READDIR);
       break;
-    }
-    sshc->sftp_handle = NULL;
-    Curl_safefree(sshc->readdir_filename);
-    sshc->readdir_filename = NULL;
-    Curl_safefree(sshc->readdir_longentry);
-    sshc->readdir_longentry = NULL;
-
-    /* no data to transfer */
-    result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
-    state(conn, SSH_STOP);
-    break;
 
-  case SSH_SFTP_DOWNLOAD_INIT:
-    /*
-     * Work on getting the specified file
-     */
-    sshc->sftp_handle =
-      libssh2_sftp_open(sshc->sftp_session, sftp_scp->path,
-                        LIBSSH2_FXF_READ, data->set.new_file_perms);
-    if(!sshc->sftp_handle) {
-      if(libssh2_session_last_errno(sshc->ssh_session) ==
+    case SSH_SFTP_READDIR_DONE:
+      if(libssh2_sftp_closedir(sshc->sftp_handle) ==
          LIBSSH2_ERROR_EAGAIN) {
         rc = LIBSSH2_ERROR_EAGAIN;
         break;
       }
-      else {
-        err = libssh2_sftp_last_error(sshc->sftp_session);
-        failf(data, "Could not open remote file for reading: %s",
-              sftp_libssh2_strerror(err));
-        state(conn, SSH_SFTP_CLOSE);
-        result = sftp_libssh2_error_to_CURLE(err);
-        sshc->actualcode = result?result:CURLE_SSH;
-        break;
-      }
-    }
-    state(conn, SSH_SFTP_DOWNLOAD_STAT);
-    break;
-
-  case SSH_SFTP_DOWNLOAD_STAT:
-  {
-    LIBSSH2_SFTP_ATTRIBUTES attrs;
+      sshc->sftp_handle = NULL;
+      Curl_safefree(sshc->readdir_filename);
+      sshc->readdir_filename = NULL;
+      Curl_safefree(sshc->readdir_longentry);
+      sshc->readdir_longentry = NULL;
 
-    rc = libssh2_sftp_stat(sshc->sftp_session, sftp_scp->path, &attrs);
-    if(rc == LIBSSH2_ERROR_EAGAIN) {
+      /* no data to transfer */
+      result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+      state(conn, SSH_STOP);
       break;
-    }
-    else if(rc) {
+
+    case SSH_SFTP_DOWNLOAD_INIT:
       /*
-       * libssh2_sftp_open() didn't return an error, so maybe the server
-       * just doesn't support stat()
+       * Work on getting the specified file
        */
-      data->req.size = -1;
-      data->req.maxdownload = -1;
-    }
-    else {
-      curl_off_t size;
-
-      size = attrs.filesize;
-      if(conn->data->state.use_range) {
-        curl_off_t from, to;
-        char *ptr;
-        char *ptr2;
-
-        from=curlx_strtoofft(conn->data->state.range, &ptr, 0);
-        while(ptr && *ptr && (isspace((int)*ptr) || (*ptr=='-')))
-          ptr++;
-        to=curlx_strtoofft(ptr, &ptr2, 0);
-        if((ptr == ptr2) /* no "to" value given */
-            || (to >= size)) {
-          to = size - 1;
-        }
-        if(from < 0) {
-          /* from is relative to end of file */
-          from += size;
-        }
-        if(from >= size) {
-          failf(data, "Offset (%"
-                FORMAT_OFF_T ") was beyond file size (%" FORMAT_OFF_T ")",
-                from, attrs.filesize);
-          return CURLE_BAD_DOWNLOAD_RESUME;
-        }
-        if(from > to) {
-          from = to;
-          size = 0;
+      sshc->sftp_handle =
+        libssh2_sftp_open(sshc->sftp_session, sftp_scp->path,
+                          LIBSSH2_FXF_READ, data->set.new_file_perms);
+      if(!sshc->sftp_handle) {
+        if(libssh2_session_last_errno(sshc->ssh_session) ==
+           LIBSSH2_ERROR_EAGAIN) {
+          rc = LIBSSH2_ERROR_EAGAIN;
+          break;
         }
         else {
-          size = to - from + 1;
+          err = libssh2_sftp_last_error(sshc->sftp_session);
+          failf(data, "Could not open remote file for reading: %s",
+                sftp_libssh2_strerror(err));
+          state(conn, SSH_SFTP_CLOSE);
+          result = sftp_libssh2_error_to_CURLE(err);
+          sshc->actualcode = result?result:CURLE_SSH;
+          break;
         }
-
-        SFTP_SEEK(conn->proto.sshc.sftp_handle, from);
       }
-      data->req.size = size;
-      data->req.maxdownload = size;
-      Curl_pgrsSetDownloadSize(data, size);
-    }
+      state(conn, SSH_SFTP_DOWNLOAD_STAT);
+      break;
 
-    /* We can resume if we can seek to the resume position */
-    if(data->state.resume_from) {
-      if(data->state.resume_from< 0) {
-        /* We're supposed to download the last abs(from) bytes */
-        if((curl_off_t)attrs.filesize < -data->state.resume_from) {
-          failf(data, "Offset (%"
-                FORMAT_OFF_T ") was beyond file size (%" FORMAT_OFF_T ")",
-                data->state.resume_from, attrs.filesize);
-          return CURLE_BAD_DOWNLOAD_RESUME;
-        }
-        /* download from where? */
-        data->state.resume_from = attrs.filesize - data->state.resume_from;
+    case SSH_SFTP_DOWNLOAD_STAT:
+    {
+      LIBSSH2_SFTP_ATTRIBUTES attrs;
+
+      rc = libssh2_sftp_stat(sshc->sftp_session, sftp_scp->path, &attrs);
+      if(rc == LIBSSH2_ERROR_EAGAIN) {
+        break;
+      }
+      else if(rc) {
+        /*
+         * libssh2_sftp_open() didn't return an error, so maybe the server
+         * just doesn't support stat()
+         */
+        data->req.size = -1;
+        data->req.maxdownload = -1;
       }
       else {
-        if((curl_off_t)attrs.filesize < data->state.resume_from) {
-          failf(data, "Offset (%" FORMAT_OFF_T
-                ") was beyond file size (%" FORMAT_OFF_T ")",
-                data->state.resume_from, attrs.filesize);
-          return CURLE_BAD_DOWNLOAD_RESUME;
-        }
-      }
-      /* Does a completed file need to be seeked and started or closed ? */
-      /* Now store the number of bytes we are expected to download */
-      data->req.size = attrs.filesize - data->state.resume_from;
-      data->req.maxdownload = attrs.filesize - data->state.resume_from;
-      Curl_pgrsSetDownloadSize(data,
-                               attrs.filesize - data->state.resume_from);
-      SFTP_SEEK(sshc->sftp_handle, data->state.resume_from);
+        curl_off_t size;
+
+        size = attrs.filesize;
+        if(conn->data->state.use_range) {
+          curl_off_t from, to;
+          char *ptr;
+          char *ptr2;
+
+          from=curlx_strtoofft(conn->data->state.range, &ptr, 0);
+          while(ptr && *ptr && (isspace((int)*ptr) || (*ptr=='-')))
+            ptr++;
+          to=curlx_strtoofft(ptr, &ptr2, 0);
+          if((ptr == ptr2) /* no "to" value given */
+             || (to >= size)) {
+            to = size - 1;
+          }
+          if(from < 0) {
+            /* from is relative to end of file */
+            from += size;
+          }
+          if(from >= size) {
+            failf(data, "Offset (%"
+                  FORMAT_OFF_T ") was beyond file size (%" FORMAT_OFF_T ")",
+                  from, attrs.filesize);
+            return CURLE_BAD_DOWNLOAD_RESUME;
+          }
+          if(from > to) {
+            from = to;
+            size = 0;
+          }
+          else {
+            size = to - from + 1;
+          }
+
+          SFTP_SEEK(conn->proto.sshc.sftp_handle, from);
+        }
+        data->req.size = size;
+        data->req.maxdownload = size;
+        Curl_pgrsSetDownloadSize(data, size);
+      }
+
+      /* We can resume if we can seek to the resume position */
+      if(data->state.resume_from) {
+        if(data->state.resume_from< 0) {
+          /* We're supposed to download the last abs(from) bytes */
+          if((curl_off_t)attrs.filesize < -data->state.resume_from) {
+            failf(data, "Offset (%"
+                  FORMAT_OFF_T ") was beyond file size (%" FORMAT_OFF_T ")",
+                  data->state.resume_from, attrs.filesize);
+            return CURLE_BAD_DOWNLOAD_RESUME;
+          }
+          /* download from where? */
+          data->state.resume_from = attrs.filesize - data->state.resume_from;
+        }
+        else {
+          if((curl_off_t)attrs.filesize < data->state.resume_from) {
+            failf(data, "Offset (%" FORMAT_OFF_T
+                  ") was beyond file size (%" FORMAT_OFF_T ")",
+                  data->state.resume_from, attrs.filesize);
+            return CURLE_BAD_DOWNLOAD_RESUME;
+          }
+        }
+        /* Does a completed file need to be seeked and started or closed ? */
+        /* Now store the number of bytes we are expected to download */
+        data->req.size = attrs.filesize - data->state.resume_from;
+        data->req.maxdownload = attrs.filesize - data->state.resume_from;
+        Curl_pgrsSetDownloadSize(data,
+                                 attrs.filesize - data->state.resume_from);
+        SFTP_SEEK(sshc->sftp_handle, data->state.resume_from);
+      }
+    }
+    /* Setup the actual download */
+    if(data->req.size == 0) {
+      /* no data to transfer */
+      result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+      infof(data, "File already completely downloaded\n");
+      state(conn, SSH_STOP);
+      break;
     }
-  }
-  /* Setup the actual download */
-  if(data->req.size == 0) {
-    /* no data to transfer */
-    result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
-    infof(data, "File already completely downloaded\n");
-    state(conn, SSH_STOP);
-    break;
-  }
-  else {
-    result = Curl_setup_transfer(conn, FIRSTSOCKET, data->req.size,
-                                 FALSE, NULL, -1, NULL);
+    else {
+      result = Curl_setup_transfer(conn, FIRSTSOCKET, data->req.size,
+                                   FALSE, NULL, -1, NULL);
 
-    /* not set by Curl_setup_transfer to preserve keepon bits */
-    conn->writesockfd = conn->sockfd;
+      /* not set by Curl_setup_transfer to preserve keepon bits */
+      conn->writesockfd = conn->sockfd;
 
-    /* FIXME: here should be explained why we need it to start the download */
-    conn->cselect_bits = CURL_CSELECT_IN;
-  }
-  if(result) {
-    state(conn, SSH_SFTP_CLOSE);
-    sshc->actualcode = result;
-  }
-  else {
-    state(conn, SSH_STOP);
-  }
-  break;
+      /* FIXME: here should be explained why we need it to start the download */
+      conn->cselect_bits = CURL_CSELECT_IN;
+    }
+    if(result) {
+      state(conn, SSH_SFTP_CLOSE);
+      sshc->actualcode = result;
+    }
+    else {
+      state(conn, SSH_STOP);
+    }
+    break;
 
-  case SSH_SFTP_CLOSE:
-    if(sshc->sftp_handle) {
-      rc = libssh2_sftp_close(sshc->sftp_handle);
-      if(rc == LIBSSH2_ERROR_EAGAIN) {
-        break;
-      }
-      else if(rc < 0) {
-        infof(data, "Failed to close libssh2 file\n");
+    case SSH_SFTP_CLOSE:
+      if(sshc->sftp_handle) {
+        rc = libssh2_sftp_close(sshc->sftp_handle);
+        if(rc == LIBSSH2_ERROR_EAGAIN) {
+          break;
+        }
+        else if(rc < 0) {
+          infof(data, "Failed to close libssh2 file\n");
+        }
+        sshc->sftp_handle = NULL;
       }
-      sshc->sftp_handle = NULL;
-    }
-    Curl_safefree(sftp_scp->path);
-    sftp_scp->path = NULL;
+      Curl_safefree(sftp_scp->path);
+      sftp_scp->path = NULL;
 
-    DEBUGF(infof(data, "SFTP DONE done\n"));
+      DEBUGF(infof(data, "SFTP DONE done\n"));
 #if 0 /* PREV */
-    state(conn, SSH_SFTP_SHUTDOWN);
+      state(conn, SSH_SFTP_SHUTDOWN);
 #endif
-    state(conn, SSH_STOP);
-    result = sshc->actualcode;
-    break;
+      state(conn, SSH_STOP);
+      result = sshc->actualcode;
+      break;
 
-  case SSH_SFTP_SHUTDOWN:
-    /* during times we get here due to a broken transfer and then the
-       sftp_handle might not have been taken down so make sure that is done
-       before we proceed */
+    case SSH_SFTP_SHUTDOWN:
+      /* during times we get here due to a broken transfer and then the
+         sftp_handle might not have been taken down so make sure that is done
+         before we proceed */
 
-    if(sshc->sftp_handle) {
-      rc = libssh2_sftp_close(sshc->sftp_handle);
-      if(rc == LIBSSH2_ERROR_EAGAIN) {
-        break;
-      }
-      else if(rc < 0) {
-        infof(data, "Failed to close libssh2 file\n");
-      }
-      sshc->sftp_handle = NULL;
-    }
-    if(sshc->sftp_session) {
-      rc = libssh2_sftp_shutdown(sshc->sftp_session);
-      if(rc == LIBSSH2_ERROR_EAGAIN) {
-        break;
+      if(sshc->sftp_handle) {
+        rc = libssh2_sftp_close(sshc->sftp_handle);
+        if(rc == LIBSSH2_ERROR_EAGAIN) {
+          break;
+        }
+        else if(rc < 0) {
+          infof(data, "Failed to close libssh2 file\n");
+        }
+        sshc->sftp_handle = NULL;
       }
-      else if(rc < 0) {
-        infof(data, "Failed to stop libssh2 sftp subsystem\n");
+      if(sshc->sftp_session) {
+        rc = libssh2_sftp_shutdown(sshc->sftp_session);
+        if(rc == LIBSSH2_ERROR_EAGAIN) {
+          break;
+        }
+        else if(rc < 0) {
+          infof(data, "Failed to stop libssh2 sftp subsystem\n");
+        }
+        sshc->sftp_session = NULL;
       }
-      sshc->sftp_session = NULL;
-    }
 
-    Curl_safefree(sshc->homedir);
-    sshc->homedir = NULL;
+      Curl_safefree(sshc->homedir);
+      sshc->homedir = NULL;
 
-    state(conn, SSH_SESSION_DISCONNECT);
-    break;
-
-  case SSH_SCP_TRANS_INIT:
-    result = ssh_getworkingpath(conn, sshc->homedir, &sftp_scp->path);
-    if(result) {
-      sshc->actualcode = result;
-      state(conn, SSH_STOP);
+      state(conn, SSH_SESSION_DISCONNECT);
       break;
-    }
 
-    if(data->set.upload) {
-      if(data->set.infilesize < 0) {
-        failf(data, "SCP requires a known file size for upload");
-        sshc->actualcode = CURLE_UPLOAD_FAILED;
-        state(conn, SSH_SCP_CHANNEL_FREE);
+    case SSH_SCP_TRANS_INIT:
+      result = ssh_getworkingpath(conn, sshc->homedir, &sftp_scp->path);
+      if(result) {
+        sshc->actualcode = result;
+        state(conn, SSH_STOP);
         break;
       }
-      state(conn, SSH_SCP_UPLOAD_INIT);
-    }
-    else {
-      state(conn, SSH_SCP_DOWNLOAD_INIT);
-    }
-    break;
 
-  case SSH_SCP_UPLOAD_INIT:
-    /*
-     * libssh2 requires that the destination path is a full path that
-     * includes the destination file and name OR ends in a "/" .  If this is
-     * not done the destination file will be named the same name as the last
-     * directory in the path.
-     */
-    sshc->ssh_channel =
-      libssh2_scp_send_ex(sshc->ssh_session, sftp_scp->path,
-                          data->set.new_file_perms,
-                          (size_t)data->set.infilesize, 0, 0);
-    if(!sshc->ssh_channel) {
-      if(libssh2_session_last_errno(sshc->ssh_session) ==
-         LIBSSH2_ERROR_EAGAIN) {
-        rc = LIBSSH2_ERROR_EAGAIN;
-        break;
+      if(data->set.upload) {
+        if(data->set.infilesize < 0) {
+          failf(data, "SCP requires a known file size for upload");
+          sshc->actualcode = CURLE_UPLOAD_FAILED;
+          state(conn, SSH_SCP_CHANNEL_FREE);
+          break;
+        }
+        state(conn, SSH_SCP_UPLOAD_INIT);
       }
       else {
-        int ssh_err;
-        char *err_msg;
-
-        ssh_err = libssh2_session_last_error(sshc->ssh_session,
-                                             &err_msg, NULL, 0);
-        failf(conn->data, "%s", err_msg);
-        state(conn, SSH_SCP_CHANNEL_FREE);
-        sshc->actualcode = libssh2_session_error_to_CURLE(ssh_err);
-        break;
+        state(conn, SSH_SCP_DOWNLOAD_INIT);
       }
-    }
+      break;
 
-    /* upload data */
-    result = Curl_setup_transfer(conn, -1, data->req.size, FALSE, NULL,
-                                 FIRSTSOCKET, NULL);
+    case SSH_SCP_UPLOAD_INIT:
+      /*
+       * libssh2 requires that the destination path is a full path that
+       * includes the destination file and name OR ends in a "/" .  If this is
+       * not done the destination file will be named the same name as the last
+       * directory in the path.
+       */
+      sshc->ssh_channel =
+        libssh2_scp_send_ex(sshc->ssh_session, sftp_scp->path,
+                            data->set.new_file_perms,
+                            (size_t)data->set.infilesize, 0, 0);
+      if(!sshc->ssh_channel) {
+        if(libssh2_session_last_errno(sshc->ssh_session) ==
+           LIBSSH2_ERROR_EAGAIN) {
+          rc = LIBSSH2_ERROR_EAGAIN;
+          break;
+        }
+        else {
+          int ssh_err;
+          char *err_msg;
+
+          ssh_err = libssh2_session_last_error(sshc->ssh_session,
+                                               &err_msg, NULL, 0);
+          failf(conn->data, "%s", err_msg);
+          state(conn, SSH_SCP_CHANNEL_FREE);
+          sshc->actualcode = libssh2_session_error_to_CURLE(ssh_err);
+          break;
+        }
+      }
 
-    /* not set by Curl_setup_transfer to preserve keepon bits */
-    conn->sockfd = conn->writesockfd;
+      /* upload data */
+      result = Curl_setup_transfer(conn, -1, data->req.size, FALSE, NULL,
+                                   FIRSTSOCKET, NULL);
 
-    if(result) {
-      state(conn, SSH_SCP_CHANNEL_FREE);
-      sshc->actualcode = result;
-    }
-    else {
-      state(conn, SSH_STOP);
-    }
-    break;
+      /* not set by Curl_setup_transfer to preserve keepon bits */
+      conn->sockfd = conn->writesockfd;
 
-  case SSH_SCP_DOWNLOAD_INIT:
-  {
-    /*
-     * We must check the remote file; if it is a directory no values will
-     * be set in sb
-     */
-    struct stat sb;
-    curl_off_t bytecount;
-
-    /* clear the struct scp recv will fill in */
-    memset(&sb, 0, sizeof(struct stat));
-
-    /* get a fresh new channel from the ssh layer */
-    sshc->ssh_channel = libssh2_scp_recv(sshc->ssh_session,
-                                         sftp_scp->path, &sb);
-    if(!sshc->ssh_channel) {
-      if(libssh2_session_last_errno(sshc->ssh_session) ==
-         LIBSSH2_ERROR_EAGAIN) {
-        rc = LIBSSH2_ERROR_EAGAIN;
-        break;
+      if(result) {
+        state(conn, SSH_SCP_CHANNEL_FREE);
+        sshc->actualcode = result;
       }
       else {
-        int ssh_err;
-        char *err_msg;
-
-        ssh_err = libssh2_session_last_error(sshc->ssh_session,
-                                             &err_msg, NULL, 0);
-        failf(conn->data, "%s", err_msg);
-        state(conn, SSH_SCP_CHANNEL_FREE);
-        sshc->actualcode = libssh2_session_error_to_CURLE(ssh_err);
-        break;
+        state(conn, SSH_STOP);
       }
-    }
-
-    /* download data */
-    bytecount = (curl_off_t)sb.st_size;
-    data->req.maxdownload =  (curl_off_t)sb.st_size;
-    result = Curl_setup_transfer(conn, FIRSTSOCKET,
-                                 bytecount, FALSE, NULL, -1, NULL);
+      break;
 
-    /* not set by Curl_setup_transfer to preserve keepon bits */
-    conn->writesockfd = conn->sockfd;
+    case SSH_SCP_DOWNLOAD_INIT:
+    {
+      /*
+       * We must check the remote file; if it is a directory no values will
+       * be set in sb
+       */
+      struct stat sb;
+      curl_off_t bytecount;
+
+      /* clear the struct scp recv will fill in */
+      memset(&sb, 0, sizeof(struct stat));
+
+      /* get a fresh new channel from the ssh layer */
+      sshc->ssh_channel = libssh2_scp_recv(sshc->ssh_session,
+                                           sftp_scp->path, &sb);
+      if(!sshc->ssh_channel) {
+        if(libssh2_session_last_errno(sshc->ssh_session) ==
+           LIBSSH2_ERROR_EAGAIN) {
+          rc = LIBSSH2_ERROR_EAGAIN;
+          break;
+        }
+        else {
+          int ssh_err;
+          char *err_msg;
+
+          ssh_err = libssh2_session_last_error(sshc->ssh_session,
+                                               &err_msg, NULL, 0);
+          failf(conn->data, "%s", err_msg);
+          state(conn, SSH_SCP_CHANNEL_FREE);
+          sshc->actualcode = libssh2_session_error_to_CURLE(ssh_err);
+          break;
+        }
+      }
 
-    /* FIXME: here should be explained why we need it to start the download */
-    conn->cselect_bits = CURL_CSELECT_IN;
+      /* download data */
+      bytecount = (curl_off_t)sb.st_size;
+      data->req.maxdownload =  (curl_off_t)sb.st_size;
+      result = Curl_setup_transfer(conn, FIRSTSOCKET,
+                                   bytecount, FALSE, NULL, -1, NULL);
 
-    if(result) {
-      state(conn, SSH_SCP_CHANNEL_FREE);
-      sshc->actualcode = result;
-    }
-    else
-      state(conn, SSH_STOP);
-  }
-  break;
+      /* not set by Curl_setup_transfer to preserve keepon bits */
+      conn->writesockfd = conn->sockfd;
 
-  case SSH_SCP_DONE:
-    if(data->set.upload)
-      state(conn, SSH_SCP_SEND_EOF);
-    else
-      state(conn, SSH_SCP_CHANNEL_FREE);
-    break;
+      /* FIXME: here should be explained why we need it to start the download */
+      conn->cselect_bits = CURL_CSELECT_IN;
 
-  case SSH_SCP_SEND_EOF:
-    if(sshc->ssh_channel) {
-      rc = libssh2_channel_send_eof(sshc->ssh_channel);
-      if(rc == LIBSSH2_ERROR_EAGAIN) {
-        break;
-      }
-      else if(rc) {
-        infof(data, "Failed to send libssh2 channel EOF\n");
+      if(result) {
+        state(conn, SSH_SCP_CHANNEL_FREE);
+        sshc->actualcode = result;
       }
+      else
+        state(conn, SSH_STOP);
     }
-    state(conn, SSH_SCP_WAIT_EOF);
     break;
 
-  case SSH_SCP_WAIT_EOF:
-    if(sshc->ssh_channel) {
-      rc = libssh2_channel_wait_eof(sshc->ssh_channel);
-      if(rc == LIBSSH2_ERROR_EAGAIN) {
-        break;
-      }
-      else if(rc) {
-        infof(data, "Failed to get channel EOF: %d\n", rc);
-      }
-    }
-    state(conn, SSH_SCP_WAIT_CLOSE);
-    break;
+    case SSH_SCP_DONE:
+      if(data->set.upload)
+        state(conn, SSH_SCP_SEND_EOF);
+      else
+        state(conn, SSH_SCP_CHANNEL_FREE);
+      break;
 
-  case SSH_SCP_WAIT_CLOSE:
-    if(sshc->ssh_channel) {
-      rc = libssh2_channel_wait_closed(sshc->ssh_channel);
-      if(rc == LIBSSH2_ERROR_EAGAIN) {
-        break;
+    case SSH_SCP_SEND_EOF:
+      if(sshc->ssh_channel) {
+        rc = libssh2_channel_send_eof(sshc->ssh_channel);
+        if(rc == LIBSSH2_ERROR_EAGAIN) {
+          break;
+        }
+        else if(rc) {
+          infof(data, "Failed to send libssh2 channel EOF\n");
+        }
       }
-      else if(rc) {
-        infof(data, "Channel failed to close: %d\n", rc);
+      state(conn, SSH_SCP_WAIT_EOF);
+      break;
+
+    case SSH_SCP_WAIT_EOF:
+      if(sshc->ssh_channel) {
+        rc = libssh2_channel_wait_eof(sshc->ssh_channel);
+        if(rc == LIBSSH2_ERROR_EAGAIN) {
+          break;
+        }
+        else if(rc) {
+          infof(data, "Failed to get channel EOF: %d\n", rc);
+        }
       }
-    }
-    state(conn, SSH_SCP_CHANNEL_FREE);
-    break;
+      state(conn, SSH_SCP_WAIT_CLOSE);
+      break;
 
-  case SSH_SCP_CHANNEL_FREE:
-    if(sshc->ssh_channel) {
-      rc = libssh2_channel_free(sshc->ssh_channel);
-      if(rc == LIBSSH2_ERROR_EAGAIN) {
-        break;
+    case SSH_SCP_WAIT_CLOSE:
+      if(sshc->ssh_channel) {
+        rc = libssh2_channel_wait_closed(sshc->ssh_channel);
+        if(rc == LIBSSH2_ERROR_EAGAIN) {
+          break;
+        }
+        else if(rc) {
+          infof(data, "Channel failed to close: %d\n", rc);
+        }
       }
-      else if(rc < 0) {
-        infof(data, "Failed to free libssh2 scp subsystem\n");
+      state(conn, SSH_SCP_CHANNEL_FREE);
+      break;
+
+    case SSH_SCP_CHANNEL_FREE:
+      if(sshc->ssh_channel) {
+        rc = libssh2_channel_free(sshc->ssh_channel);
+        if(rc == LIBSSH2_ERROR_EAGAIN) {
+          break;
+        }
+        else if(rc < 0) {
+          infof(data, "Failed to free libssh2 scp subsystem\n");
+        }
+        sshc->ssh_channel = NULL;
       }
-      sshc->ssh_channel = NULL;
-    }
-    DEBUGF(infof(data, "SCP DONE phase complete\n"));
+      DEBUGF(infof(data, "SCP DONE phase complete\n"));
 #if 0 /* PREV */
-    state(conn, SSH_SESSION_DISCONNECT);
+      state(conn, SSH_SESSION_DISCONNECT);
 #endif
-    state(conn, SSH_STOP);
-    result = sshc->actualcode;
-    break;
+      state(conn, SSH_STOP);
+      result = sshc->actualcode;
+      break;
 
-  case SSH_SESSION_DISCONNECT:
-    /* during weird times when we've been prematurely aborted, the channel
-       is still alive when we reach this state and we MUST kill the channel
-       properly first */
-    if(sshc->ssh_channel) {
-      rc = libssh2_channel_free(sshc->ssh_channel);
-      if(rc == LIBSSH2_ERROR_EAGAIN) {
-        break;
-      }
-      else if(rc < 0) {
-        infof(data, "Failed to free libssh2 scp subsystem\n");
+    case SSH_SESSION_DISCONNECT:
+      /* during weird times when we've been prematurely aborted, the channel
+         is still alive when we reach this state and we MUST kill the channel
+         properly first */
+      if(sshc->ssh_channel) {
+        rc = libssh2_channel_free(sshc->ssh_channel);
+        if(rc == LIBSSH2_ERROR_EAGAIN) {
+          break;
+        }
+        else if(rc < 0) {
+          infof(data, "Failed to free libssh2 scp subsystem\n");
+        }
+        sshc->ssh_channel = NULL;
       }
-      sshc->ssh_channel = NULL;
-    }
 
-    if(sshc->ssh_session) {
-      rc = libssh2_session_disconnect(sshc->ssh_session, "Shutdown");
-      if(rc == LIBSSH2_ERROR_EAGAIN) {
-        break;
-      }
-      else if(rc < 0) {
-        infof(data, "Failed to disconnect libssh2 session\n");
+      if(sshc->ssh_session) {
+        rc = libssh2_session_disconnect(sshc->ssh_session, "Shutdown");
+        if(rc == LIBSSH2_ERROR_EAGAIN) {
+          break;
+        }
+        else if(rc < 0) {
+          infof(data, "Failed to disconnect libssh2 session\n");
+        }
       }
-    }
 
-    Curl_safefree(sshc->homedir);
-    sshc->homedir = NULL;
+      Curl_safefree(sshc->homedir);
+      sshc->homedir = NULL;
 
-    state(conn, SSH_SESSION_FREE);
-    break;
+      state(conn, SSH_SESSION_FREE);
+      break;
 
-  case SSH_SESSION_FREE:
+    case SSH_SESSION_FREE:
 #ifdef HAVE_LIBSSH2_KNOWNHOST_API
-    if(sshc->kh) {
-      libssh2_knownhost_free(sshc->kh);
-      sshc->kh = NULL;
-    }
+      if(sshc->kh) {
+        libssh2_knownhost_free(sshc->kh);
+        sshc->kh = NULL;
+      }
 #endif
 
-    if(sshc->ssh_session) {
-      rc = libssh2_session_free(sshc->ssh_session);
-      if(rc == LIBSSH2_ERROR_EAGAIN) {
-        break;
-      }
-      else if(rc < 0) {
-        infof(data, "Failed to free libssh2 session\n");
+      if(sshc->ssh_session) {
+        rc = libssh2_session_free(sshc->ssh_session);
+        if(rc == LIBSSH2_ERROR_EAGAIN) {
+          break;
+        }
+        else if(rc < 0) {
+          infof(data, "Failed to free libssh2 session\n");
+        }
+        sshc->ssh_session = NULL;
       }
-      sshc->ssh_session = NULL;
+      conn->bits.close = TRUE;
+      sshc->nextstate = SSH_NO_STATE;
+      state(conn, SSH_STOP);
+      result = sshc->actualcode;
+      break;
+
+    case SSH_QUIT:
+      /* fallthrough, just stop! */
+    default:
+      /* internal error */
+      sshc->nextstate = SSH_NO_STATE;
+      state(conn, SSH_STOP);
+      break;
     }
-    conn->bits.close = TRUE;
-    sshc->nextstate = SSH_NO_STATE;
-    state(conn, SSH_STOP);
-    result = sshc->actualcode;
-    break;
 
-  case SSH_QUIT:
-    /* fallthrough, just stop! */
-  default:
-    /* internal error */
-    sshc->nextstate = SSH_NO_STATE;
-    state(conn, SSH_STOP);
-    break;
-  }
+  } while(!rc && (sshc->state != SSH_STOP));
 
   if(rc == LIBSSH2_ERROR_EAGAIN) {
     /* we would block, we need to wait for the socket to be ready (in the