Commit 08368933 authored by Daniel Stenberg's avatar Daniel Stenberg
Browse files

Mike Protts brought a patch that makes resumed transfers work with SFTP.

parent 590f0358
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -6,6 +6,9 @@

                                  Changelog

Daniel S (4 Mar 2008)
- Mike Protts brought a patch that makes resumed transfers work with SFTP.

Daniel S (1 Mar 2008)
- Anatoli Tubman found and fixed a crash with Negotiate authentication used on
  a re-used connection where both requests used Negotiate.
+2 −1
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@ This release includes the following changes:
 o SSLv2 is now disabled by default for SSL operations
 o the test509-style setting URL in callback is officially no longer supported
 o support a full chain of certificates in a given PKCS12 certificate
 o resumed transfers work with SFTP

This release includes the following bugfixes:

@@ -52,6 +53,6 @@ advice from friends like these:
 Michal Marek, Dmitry Kurochkin, Niklas Angebrand, Günter Knauf, Yang Tse,
 Dan Fandrich, Mike Hommey, Pooyan McSporran, Jerome Muffat-Meridol,
 Kaspar Brand, Gautam Kachroo, Zmey Petroff, Georg Lippitsch, Sam Listopad,
 Anatoli Tubman
 Anatoli Tubman, Mike Protts

        Thanks! (and sorry if I forgot to mention someone)
+111 −3
Original line number Diff line number Diff line
@@ -844,7 +844,6 @@ static CURLcode ssh_statemach_act(struct connectdata *conn)
      break;
    }
    else if(sshc->quote_item->data) {
      fprintf(stderr, "data: %s\n", 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
@@ -1195,10 +1194,31 @@ static CURLcode ssh_statemach_act(struct connectdata *conn)
     *          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;
        }
      }
    }

    sshc->sftp_handle =
      libssh2_sftp_open(sshc->sftp_session, sftp_scp->path,
                        /* If we have restart position then open for append */
                        (data->state.resume_from > 0)?
                        LIBSSH2_FXF_WRITE|LIBSSH2_FXF_APPEND:
                        LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC,
                        data->set.new_file_perms);

    if(!sshc->sftp_handle) {
      if(libssh2_session_last_errno(sshc->ssh_session) ==
         LIBSSH2_ERROR_EAGAIN) {
@@ -1228,6 +1248,56 @@ static CURLcode ssh_statemach_act(struct connectdata *conn)
      }
    }

    /* 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) {
        curl_off_t readthisamountnow = data->state.resume_from;

        if(conn->seek_func(conn->seek_client,
                           readthisamountnow, SEEK_SET) != 0) {
          failf(data, "Could not seek stream");
          return CURLE_FTP_COULDNT_USE_REST;
        }
      }
      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);
      }

      libssh2_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);
@@ -1552,11 +1622,49 @@ static CURLcode ssh_statemach_act(struct connectdata *conn)
      data->req.maxdownload = attrs.filesize;
      Curl_pgrsSetDownloadSize(data, attrs.filesize);
    }
  }

    /* 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);
      libssh2_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;
  }
  else {
    result = Curl_setup_transfer(conn, FIRSTSOCKET, data->req.size,
                               FALSE, NULL, -1, NULL);
  }
  if(result) {
    state(conn, SSH_SFTP_CLOSE);
    sshc->actualcode = result;