From 008b848dccafc18df79e0de9163b0bfab4f5392c Mon Sep 17 00:00:00 2001
From: Daniel Stenberg <daniel@haxx.se>
Date: Mon, 15 Dec 2008 23:04:51 +0000
Subject: [PATCH] - libssh2_sftp_last_error() was wrongly used at some places
 in libcurl which   made libcurl sometimes not properly abort problematic SFTP
 transfers.

---
 CHANGES       |  4 ++++
 RELEASE-NOTES |  1 +
 lib/ssh.c     | 44 ++++++++++++++++++++++++++++++++------------
 3 files changed, 37 insertions(+), 12 deletions(-)

diff --git a/CHANGES b/CHANGES
index eaee3cb548..ba21b3f464 100644
--- a/CHANGES
+++ b/CHANGES
@@ -6,6 +6,10 @@
 
                                   Changelog
 
+Daniel Stenberg (16 Dec 2008)
+- libssh2_sftp_last_error() was wrongly used at some places in libcurl which
+  made libcurl sometimes not properly abort problematic SFTP transfers.
+
 Daniel Stenberg (12 Dec 2008)
 - More work with Igor Novoseltsev to first fix the remaining stuff for
   removing easy handles from multi handles when the easy handle is/was within
diff --git a/RELEASE-NOTES b/RELEASE-NOTES
index 96a3001abb..6183d4364c 100644
--- a/RELEASE-NOTES
+++ b/RELEASE-NOTES
@@ -30,6 +30,7 @@ This release includes the following bugfixes:
  o dotted IPv6 addresses longer than 39 bytes failed
  o curl_easy_duphandle() doesn't try to duplicate the connection cache pointer
  o build failure on OS/400 when enabling IPv6
+ o better detection of SFTP failures
 
 This release includes the following known bugs:
 
diff --git a/lib/ssh.c b/lib/ssh.c
index f826a4fa4b..c97d0c7e88 100644
--- a/lib/ssh.c
+++ b/lib/ssh.c
@@ -778,6 +778,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
       /* 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;
@@ -1238,16 +1239,22 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
                         flags, data->set.new_file_perms);
 
     if(!sshc->sftp_handle) {
-      if(libssh2_session_last_errno(sshc->ssh_session) ==
-         LIBSSH2_ERROR_EAGAIN) {
-        rc = LIBSSH2_ERROR_EAGAIN;
+      rc = libssh2_session_last_errno(sshc->ssh_session);
+
+      if(LIBSSH2_ERROR_EAGAIN == rc)
         break;
-      }
       else {
-        err = libssh2_sftp_last_error(sshc->sftp_session);
+        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) {
           state(conn, SSH_SFTP_CLOSE);
-          sshc->actualcode = sftp_libssh2_error_to_CURLE(err);
+          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;
@@ -1263,8 +1270,18 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
           break;
         }
         state(conn, SSH_SFTP_CLOSE);
-        sshc->actualcode = sftp_libssh2_error_to_CURLE(err);
-        failf(data, "Upload failed: %s", sftp_libssh2_strerror(err));
+        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;
       }
     }
@@ -1378,7 +1395,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
          (sftp_err != LIBSSH2_FX_PERMISSION_DENIED)) {
         result = sftp_libssh2_error_to_CURLE(sftp_err);
         state(conn, SSH_SFTP_CLOSE);
-        sshc->actualcode = result;
+        sshc->actualcode = result?result:CURLE_SSH;
         break;
       }
     }
@@ -1403,7 +1420,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
         failf(data, "Could not open directory for reading: %s",
               sftp_libssh2_strerror(err));
         state(conn, SSH_SFTP_CLOSE);
-        sshc->actualcode = sftp_libssh2_error_to_CURLE(err);
+        result = sftp_libssh2_error_to_CURLE(err);
+        sshc->actualcode = result?result:CURLE_SSH;
         break;
       }
     }
@@ -1512,7 +1530,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
     }
     else if(sshc->readdir_len <= 0) {
       err = libssh2_sftp_last_error(sshc->sftp_session);
-      sshc->actualcode = sftp_libssh2_error_to_CURLE(err);
+      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));
@@ -1621,7 +1640,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
         failf(data, "Could not open remote file for reading: %s",
               sftp_libssh2_strerror(err));
         state(conn, SSH_SFTP_CLOSE);
-        sshc->actualcode = sftp_libssh2_error_to_CURLE(err);
+        result = sftp_libssh2_error_to_CURLE(err);
+        sshc->actualcode = result?result:CURLE_SSH;
         break;
       }
     }
-- 
GitLab