diff --git a/CHANGES b/CHANGES
index 258c4b248679867699162d689ea4b6171195fadf..ef250ba33964f8aa17e116506f3f2a30483200d9 100644
--- a/CHANGES
+++ b/CHANGES
@@ -6,6 +6,13 @@
 
                                   Changelog
 
+Daniel Fandrich (10 Jul 2008)
+- Changed slightly the SFTP quote commands chmod, chown and chgrp to only
+  set the attribute that has changed instead of all possible ones. Hopefully,
+  this will solve the "Permission denied" problem that Nagarajan Sreenivasan
+  reported when setting some modes, but regardless, it saves a protocol
+  round trip in the chmod case.
+
 Yang Tse (10 Jul 2008)
 - Peter Lamberg filed bug report #2015126: "poll gives WSAEINVAL when POLLPRI
   is set in fdset.events" (http://curl.haxx.se/bug/view.cgi?id=2015126) which
diff --git a/lib/ssh.c b/lib/ssh.c
index 6f2392d6d6bac20bbed41ab70b401e449275322a..cb6e96c780065f75a0e3280aa499e99cb10dcf41 100644
--- a/lib/ssh.c
+++ b/lib/ssh.c
@@ -997,27 +997,34 @@ static CURLcode ssh_statemach_act(struct connectdata *conn)
     break;
 
   case SSH_SFTP_QUOTE_STAT:
-    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 = CURLE_QUOTE_ERROR;
-      break;
+    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 = CURLE_QUOTE_ERROR;
+	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])) {
         Curl_safefree(sshc->quote_path1);
         sshc->quote_path1 = NULL;
@@ -1031,6 +1038,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn)
     }
     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])) {
@@ -1046,6 +1054,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn)
     }
     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;