diff --git a/lib/vssh/libssh2.c b/lib/vssh/libssh2.c index e733999387..40858d18c0 100644 --- a/lib/vssh/libssh2.c +++ b/lib/vssh/libssh2.c @@ -1801,10 +1801,15 @@ static CURLcode ssh_state_sftp_realpath(struct Curl_easy *data, /* * Get the "home" directory */ - int rc = libssh2_sftp_symlink_ex(sshc->sftp_session, - ".", curlx_uztoui(strlen(".")), - sshp->readdir_filename, CURL_PATH_MAX, - LIBSSH2_SFTP_REALPATH); + int rc; + + if(!sshp) + return CURLE_FAILED_INIT; + + rc = libssh2_sftp_symlink_ex(sshc->sftp_session, ".", + curlx_uztoui(strlen(".")), + sshp->readdir_filename, CURL_PATH_MAX, + LIBSSH2_SFTP_REALPATH); if(rc == LIBSSH2_ERROR_EAGAIN) return CURLE_AGAIN; @@ -1844,7 +1849,12 @@ static CURLcode ssh_state_sftp_quote_init(struct Curl_easy *data, struct ssh_conn *sshc, struct SSHPROTO *sshp) { - CURLcode result = Curl_getworkingpath(data, sshc->homedir, &sshp->path); + CURLcode result; + + if(!sshp) + return CURLE_FAILED_INIT; + + result = Curl_getworkingpath(data, sshc->homedir, &sshp->path); if(result) { myssh_to(data, sshc, SSH_STOP); return result; @@ -1880,7 +1890,12 @@ static CURLcode ssh_state_sftp_quote(struct Curl_easy *data, struct SSHPROTO *sshp) { /* Send quote commands */ - CURLcode result = sftp_quote(data, sshc, sshp); + CURLcode result; + + if(!sshp) + return CURLE_FAILED_INIT; + + result = sftp_quote(data, sshc, sshp); if(result) { myssh_to(data, sshc, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; @@ -1916,7 +1931,12 @@ static CURLcode ssh_state_sftp_quote_stat(struct Curl_easy *data, struct SSHPROTO *sshp, bool *blockp) { - CURLcode result = sftp_quote_stat(data, sshc, sshp, blockp); + CURLcode result; + + if(!sshp) + return CURLE_FAILED_INIT; + + result = sftp_quote_stat(data, sshc, sshp, blockp); if(result) { myssh_to(data, sshc, SSH_SFTP_CLOSE); sshc->nextstate = SSH_NO_STATE; @@ -1928,11 +1948,15 @@ static CURLcode ssh_state_sftp_quote_setstat(struct Curl_easy *data, struct ssh_conn *sshc, struct SSHPROTO *sshp) { - int rc = - libssh2_sftp_stat_ex(sshc->sftp_session, sshc->quote_path2, - curlx_uztoui(strlen(sshc->quote_path2)), - LIBSSH2_SFTP_SETSTAT, - &sshp->quote_attrs); + int rc; + + if(!sshp) + return CURLE_FAILED_INIT; + + rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshc->quote_path2, + curlx_uztoui(strlen(sshc->quote_path2)), + LIBSSH2_SFTP_SETSTAT, + &sshp->quote_attrs); if(rc == LIBSSH2_ERROR_EAGAIN) return CURLE_AGAIN; @@ -2139,9 +2163,14 @@ static CURLcode ssh_state_sftp_create_dirs_mkdir(struct Curl_easy *data, struct SSHPROTO *sshp) { /* 'mode' - parameter is preliminary - default to 0644 */ - int rc = libssh2_sftp_mkdir_ex(sshc->sftp_session, sshp->path, - curlx_uztoui(strlen(sshp->path)), - (long)data->set.new_directory_perms); + int rc; + + if(!sshp) + return CURLE_FAILED_INIT; + + rc = libssh2_sftp_mkdir_ex(sshc->sftp_session, sshp->path, + curlx_uztoui(strlen(sshp->path)), + (long)data->set.new_directory_perms); if(rc == LIBSSH2_ERROR_EAGAIN) return CURLE_AGAIN; @@ -2169,6 +2198,9 @@ static CURLcode ssh_state_sftp_readdir_init(struct Curl_easy *data, struct ssh_conn *sshc, struct SSHPROTO *sshp) { + if(!sshp) + return CURLE_FAILED_INIT; + Curl_pgrsSetDownloadSize(data, -1); if(data->req.no_body) { myssh_to(data, sshc, SSH_STOP); @@ -2203,13 +2235,16 @@ static CURLcode ssh_state_sftp_readdir_link(struct Curl_easy *data, struct SSHPROTO *sshp) { CURLcode result; - int rc = - libssh2_sftp_symlink_ex(sshc->sftp_session, - curlx_dyn_ptr(&sshp->readdir_link), - (unsigned int) - curlx_dyn_len(&sshp->readdir_link), - sshp->readdir_filename, - CURL_PATH_MAX, LIBSSH2_SFTP_READLINK); + int rc; + if(!sshp) + return CURLE_FAILED_INIT; + + rc = libssh2_sftp_symlink_ex(sshc->sftp_session, + curlx_dyn_ptr(&sshp->readdir_link), + (unsigned int) + curlx_dyn_len(&sshp->readdir_link), + sshp->readdir_filename, + CURL_PATH_MAX, LIBSSH2_SFTP_READLINK); if(rc == LIBSSH2_ERROR_EAGAIN) return CURLE_AGAIN; @@ -2232,7 +2267,10 @@ static CURLcode ssh_state_scp_download_init(struct Curl_easy *data, struct SSHPROTO *sshp) { curl_off_t bytecount; + libssh2_struct_stat sb; + if(!sshp) + return CURLE_FAILED_INIT; /* * We must check the remote file; if it is a directory no values are * be set in sb @@ -2243,7 +2281,6 @@ static CURLcode ssh_state_scp_download_init(struct Curl_easy *data, */ /* get a fresh new channel from the ssh layer */ - libssh2_struct_stat sb; memset(&sb, 0, sizeof(libssh2_struct_stat)); sshc->ssh_channel = libssh2_scp_recv2(sshc->ssh_session, sshp->path, &sb); if(!sshc->ssh_channel) { @@ -2277,6 +2314,8 @@ static CURLcode ssh_state_sftp_close(struct Curl_easy *data, struct SSHPROTO *sshp) { int rc = 0; + if(!sshp) + return CURLE_FAILED_INIT; if(sshc->sftp_handle) { rc = libssh2_sftp_close(sshc->sftp_handle); if(rc == LIBSSH2_ERROR_EAGAIN) @@ -2348,6 +2387,8 @@ static CURLcode ssh_state_sftp_download_init(struct Curl_easy *data, struct ssh_conn *sshc, struct SSHPROTO *sshp) { + if(!sshp) + return CURLE_FAILED_INIT; /* * Work on getting the specified file */ @@ -2376,6 +2417,8 @@ static CURLcode ssh_state_scp_upload_init(struct Curl_easy *data, struct ssh_conn *sshc, struct SSHPROTO *sshp) { + if(!sshp) + return CURLE_FAILED_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 @@ -2556,6 +2599,307 @@ static CURLcode sshc_cleanup(struct ssh_conn *sshc, struct Curl_easy *data, return CURLE_OK; } +static CURLcode ssh_state_sftp_getinfo(struct Curl_easy *data, + struct ssh_conn *sshc) +{ + if(data->set.get_filetime) + myssh_to(data, sshc, SSH_SFTP_FILETIME); + else + myssh_to(data, sshc, SSH_SFTP_TRANS_INIT); + return CURLE_OK; +} + +static CURLcode ssh_state_sftp_filetime(struct Curl_easy *data, + struct ssh_conn *sshc, + struct SSHPROTO *sshp) +{ + LIBSSH2_SFTP_ATTRIBUTES attrs; + int rc; + + if(!sshp) + return CURLE_FAILED_INIT; + + rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshp->path, + curlx_uztoui(strlen(sshp->path)), + LIBSSH2_SFTP_STAT, &attrs); + if(rc == LIBSSH2_ERROR_EAGAIN) + return CURLE_AGAIN; + + if(rc == 0) + data->info.filetime = (time_t)attrs.mtime; + + myssh_to(data, sshc, SSH_SFTP_TRANS_INIT); + return CURLE_OK; +} + +static CURLcode ssh_state_sftp_trans_init(struct Curl_easy *data, + struct ssh_conn *sshc, + struct SSHPROTO *sshp) +{ + if(data->state.upload) + myssh_to(data, sshc, SSH_SFTP_UPLOAD_INIT); + else if(sshp) { + size_t plen = strlen(sshp->path); + if(plen && (sshp->path[plen - 1] == '/')) + myssh_to(data, sshc, SSH_SFTP_READDIR_INIT); + else + myssh_to(data, sshc, SSH_SFTP_DOWNLOAD_INIT); + } + else + return CURLE_FAILED_INIT; + return CURLE_OK; +} + +static CURLcode ssh_state_sftp_upload_init(struct Curl_easy *data, + struct ssh_conn *sshc, + struct SSHPROTO *sshp, + bool *block) +{ + CURLcode result; + if(!sshp) + return CURLE_FAILED_INIT; + result = sftp_upload_init(data, sshc, sshp, block); + if(result) { + myssh_to(data, sshc, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + } + return result; +} + +static CURLcode ssh_state_sftp_create_dirs_init(struct Curl_easy *data, + struct ssh_conn *sshc, + struct SSHPROTO *sshp) +{ + if(!sshp) + return CURLE_FAILED_INIT; + if(strlen(sshp->path) > 1) { + sshc->slash_pos = sshp->path + 1; /* ignore the leading '/' */ + myssh_to(data, sshc, SSH_SFTP_CREATE_DIRS); + } + else + myssh_to(data, sshc, SSH_SFTP_UPLOAD_INIT); + return CURLE_OK; +} + +static CURLcode ssh_state_sftp_create_dirs(struct Curl_easy *data, + struct ssh_conn *sshc, + struct SSHPROTO *sshp) +{ + if(!sshp) + return CURLE_FAILED_INIT; + sshc->slash_pos = strchr(sshc->slash_pos, '/'); + if(sshc->slash_pos) { + *sshc->slash_pos = 0; + infof(data, "Creating directory '%s'", sshp->path); + myssh_to(data, sshc, SSH_SFTP_CREATE_DIRS_MKDIR); + return CURLE_OK; + } + myssh_to(data, sshc, SSH_SFTP_UPLOAD_INIT); + return CURLE_OK; +} + +static CURLcode ssh_state_sftp_readdir(struct Curl_easy *data, + struct ssh_conn *sshc, + struct SSHPROTO *sshp, + bool *block) +{ + CURLcode result; + if(!sshp) + return CURLE_FAILED_INIT; + result = sftp_readdir(data, sshc, sshp, block); + if(result) + myssh_to(data, sshc, SSH_SFTP_CLOSE); + return result; +} + +static CURLcode ssh_state_sftp_readdir_bottom(struct Curl_easy *data, + struct ssh_conn *sshc, + struct SSHPROTO *sshp) +{ + CURLcode result; + if(!sshp) + return CURLE_FAILED_INIT; + + result = curlx_dyn_addn(&sshp->readdir, "\n", 1); + if(!result) + result = Curl_client_write(data, CLIENTWRITE_BODY, + curlx_dyn_ptr(&sshp->readdir), + curlx_dyn_len(&sshp->readdir)); + if(result) { + curlx_dyn_free(&sshp->readdir); + myssh_to(data, sshc, SSH_STOP); + } + else { + curlx_dyn_reset(&sshp->readdir); + myssh_to(data, sshc, SSH_SFTP_READDIR); + } + return result; +} + +static CURLcode ssh_state_sftp_readdir_done(struct Curl_easy *data, + struct ssh_conn *sshc) +{ + if(libssh2_sftp_closedir(sshc->sftp_handle) == + LIBSSH2_ERROR_EAGAIN) + return CURLE_AGAIN; + + sshc->sftp_handle = NULL; + + /* no data to transfer */ + Curl_xfer_setup_nop(data); + myssh_to(data, sshc, SSH_STOP); + return CURLE_OK; +} + +static CURLcode ssh_state_sftp_download_stat(struct Curl_easy *data, + struct ssh_conn *sshc, + struct SSHPROTO *sshp, + bool *block) +{ + CURLcode result; + if(!sshp) + return CURLE_FAILED_INIT; + result = sftp_download_stat(data, sshc, sshp, block); + if(result) { + myssh_to(data, sshc, SSH_SFTP_CLOSE); + sshc->nextstate = SSH_NO_STATE; + } + return result; +} + +static CURLcode ssh_state_scp_trans_init(struct Curl_easy *data, + struct ssh_conn *sshc, + struct SSHPROTO *sshp) +{ + CURLcode result; + if(!sshp) + return CURLE_FAILED_INIT; + result = Curl_getworkingpath(data, sshc->homedir, + &sshp->path); + if(result) { + myssh_to(data, sshc, SSH_STOP); + return result; + } + + if(data->state.upload) { + if(data->state.infilesize < 0) { + failf(data, "SCP requires a known file size for upload"); + myssh_to(data, sshc, SSH_SCP_CHANNEL_FREE); + return CURLE_UPLOAD_FAILED; + } + myssh_to(data, sshc, SSH_SCP_UPLOAD_INIT); + } + else + myssh_to(data, sshc, SSH_SCP_DOWNLOAD_INIT); + return CURLE_OK; +} + +static CURLcode ssh_state_scp_done(struct Curl_easy *data, + struct ssh_conn *sshc) +{ + if(data->state.upload) + myssh_to(data, sshc, SSH_SCP_SEND_EOF); + else + myssh_to(data, sshc, SSH_SCP_CHANNEL_FREE); + return CURLE_OK; +} + +static CURLcode ssh_state_scp_send_eof(struct Curl_easy *data, + struct ssh_conn *sshc) +{ + if(sshc->ssh_channel) { + int rc = libssh2_channel_send_eof(sshc->ssh_channel); + if(rc == LIBSSH2_ERROR_EAGAIN) + return CURLE_AGAIN; + if(rc) { + char *err_msg = NULL; + (void)libssh2_session_last_error(sshc->ssh_session, + &err_msg, NULL, 0); + infof(data, + "Failed to send libssh2 channel EOF: %d %s", + rc, err_msg); + } + } + myssh_to(data, sshc, SSH_SCP_WAIT_EOF); + return CURLE_OK; +} + +static CURLcode ssh_state_scp_wait_eof(struct Curl_easy *data, + struct ssh_conn *sshc) +{ + if(sshc->ssh_channel) { + int rc = libssh2_channel_wait_eof(sshc->ssh_channel); + if(rc == LIBSSH2_ERROR_EAGAIN) + return CURLE_AGAIN; + if(rc) { + char *err_msg = NULL; + (void)libssh2_session_last_error(sshc->ssh_session, + &err_msg, NULL, 0); + infof(data, "Failed to get channel EOF: %d %s", + rc, err_msg); + } + } + myssh_to(data, sshc, SSH_SCP_WAIT_CLOSE); + return CURLE_OK; +} + +static CURLcode ssh_state_scp_wait_close(struct Curl_easy *data, + struct ssh_conn *sshc) +{ + if(sshc->ssh_channel) { + int rc = + libssh2_channel_wait_closed(sshc->ssh_channel); + if(rc == LIBSSH2_ERROR_EAGAIN) + return CURLE_AGAIN; + if(rc) { + char *err_msg = NULL; + (void)libssh2_session_last_error(sshc->ssh_session, + &err_msg, NULL, 0); + infof(data, "Channel failed to close: %d %s", + rc, err_msg); + } + } + myssh_to(data, sshc, SSH_SCP_CHANNEL_FREE); + return CURLE_OK; +} + +static CURLcode ssh_state_scp_channel_free( + struct Curl_easy *data, + struct ssh_conn *sshc) +{ + if(sshc->ssh_channel) { + int rc = libssh2_channel_free(sshc->ssh_channel); + if(rc == LIBSSH2_ERROR_EAGAIN) + return CURLE_AGAIN; + if(rc < 0) { + char *err_msg = NULL; + (void)libssh2_session_last_error(sshc->ssh_session, + &err_msg, NULL, 0); + infof(data, + "Failed to free libssh2 scp subsystem: %d %s", + rc, err_msg); + } + sshc->ssh_channel = NULL; + } + CURL_TRC_SSH(data, "SCP DONE phase complete"); + myssh_to(data, sshc, SSH_STOP); + return CURLE_OK; +} + +static CURLcode ssh_state_session_free(struct Curl_easy *data, + struct ssh_conn *sshc) +{ + CURLcode result = sshc_cleanup(sshc, data, FALSE); + struct connectdata *conn = data->conn; + if(result) + return result; + memset(sshc, 0, sizeof(struct ssh_conn)); + connclose(conn, "SSH session free"); + sshc->state = SSH_SESSION_FREE; /* current */ + myssh_to(data, sshc, SSH_STOP); + return CURLE_OK; +} + /* * ssh_statemachine() runs the SSH state machine as far as it can without * blocking and without reaching the end. The data the pointer 'block' points @@ -2568,7 +2912,6 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, bool *block) { CURLcode result = CURLE_OK; - struct connectdata *conn = data->conn; *block = 0; /* we are not blocking by default */ do { @@ -2646,13 +2989,11 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, break; case SSH_SFTP_REALPATH: - result = sshp ? ssh_state_sftp_realpath(data, sshc, sshp) : - CURLE_FAILED_INIT; + result = ssh_state_sftp_realpath(data, sshc, sshp); break; case SSH_SFTP_QUOTE_INIT: - result = sshp ? ssh_state_sftp_quote_init(data, sshc, sshp) : - CURLE_FAILED_INIT; + result = ssh_state_sftp_quote_init(data, sshc, sshp); break; case SSH_SFTP_POSTQUOTE_INIT: @@ -2660,8 +3001,7 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, break; case SSH_SFTP_QUOTE: - result = sshp ? ssh_state_sftp_quote(data, sshc, sshp) : - CURLE_FAILED_INIT; + result = ssh_state_sftp_quote(data, sshc, sshp); break; case SSH_SFTP_NEXT_QUOTE: @@ -2669,13 +3009,11 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, break; case SSH_SFTP_QUOTE_STAT: - result = sshp ? ssh_state_sftp_quote_stat(data, sshc, sshp, block) : - CURLE_FAILED_INIT; + result = ssh_state_sftp_quote_stat(data, sshc, sshp, block); break; case SSH_SFTP_QUOTE_SETSTAT: - result = sshp ? ssh_state_sftp_quote_setstat(data, sshc, sshp) : - CURLE_FAILED_INIT; + result = ssh_state_sftp_quote_setstat(data, sshc, sshp); break; case SSH_SFTP_QUOTE_SYMLINK: @@ -2703,160 +3041,63 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, break; case SSH_SFTP_GETINFO: - if(data->set.get_filetime) { - myssh_to(data, sshc, SSH_SFTP_FILETIME); - } - else { - myssh_to(data, sshc, SSH_SFTP_TRANS_INIT); - } + result = ssh_state_sftp_getinfo(data, sshc); break; - case SSH_SFTP_FILETIME: { - LIBSSH2_SFTP_ATTRIBUTES attrs; - int rc; - - if(!sshp) { - result = CURLE_FAILED_INIT; - break; - } - rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshp->path, - curlx_uztoui(strlen(sshp->path)), - LIBSSH2_SFTP_STAT, &attrs); - if(rc == LIBSSH2_ERROR_EAGAIN) { - result = CURLE_AGAIN; - break; - } - if(rc == 0) { - data->info.filetime = (time_t)attrs.mtime; - } - - myssh_to(data, sshc, SSH_SFTP_TRANS_INIT); + case SSH_SFTP_FILETIME: + result = ssh_state_sftp_filetime(data, sshc, sshp); break; - } case SSH_SFTP_TRANS_INIT: - if(data->state.upload) - myssh_to(data, sshc, SSH_SFTP_UPLOAD_INIT); - else if(sshp) { - if(sshp->path[strlen(sshp->path) - 1] == '/') - myssh_to(data, sshc, SSH_SFTP_READDIR_INIT); - else - myssh_to(data, sshc, SSH_SFTP_DOWNLOAD_INIT); - } - else - result = CURLE_FAILED_INIT; + result = ssh_state_sftp_trans_init(data, sshc, sshp); break; case SSH_SFTP_UPLOAD_INIT: - result = sshp ? sftp_upload_init(data, sshc, sshp, block) : - CURLE_FAILED_INIT; - if(result) { - myssh_to(data, sshc, SSH_SFTP_CLOSE); - sshc->nextstate = SSH_NO_STATE; - } + result = ssh_state_sftp_upload_init(data, sshc, sshp, block); break; case SSH_SFTP_CREATE_DIRS_INIT: - if(!sshp) - result = CURLE_FAILED_INIT; - else if(strlen(sshp->path) > 1) { - sshc->slash_pos = sshp->path + 1; /* ignore the leading '/' */ - myssh_to(data, sshc, SSH_SFTP_CREATE_DIRS); - } - else { - myssh_to(data, sshc, SSH_SFTP_UPLOAD_INIT); - } + result = ssh_state_sftp_create_dirs_init(data, sshc, sshp); break; case SSH_SFTP_CREATE_DIRS: - if(!sshp) { - result = CURLE_FAILED_INIT; - break; - } - sshc->slash_pos = strchr(sshc->slash_pos, '/'); - if(sshc->slash_pos) { - *sshc->slash_pos = 0; - - infof(data, "Creating directory '%s'", sshp->path); - myssh_to(data, sshc, SSH_SFTP_CREATE_DIRS_MKDIR); - break; - } - myssh_to(data, sshc, SSH_SFTP_UPLOAD_INIT); + result = ssh_state_sftp_create_dirs(data, sshc, sshp); break; case SSH_SFTP_CREATE_DIRS_MKDIR: - result = sshp ? ssh_state_sftp_create_dirs_mkdir(data, sshc, sshp) : - CURLE_FAILED_INIT; + result = ssh_state_sftp_create_dirs_mkdir(data, sshc, sshp); break; case SSH_SFTP_READDIR_INIT: - result = sshp ? ssh_state_sftp_readdir_init(data, sshc, sshp) : - CURLE_FAILED_INIT; + result = ssh_state_sftp_readdir_init(data, sshc, sshp); break; case SSH_SFTP_READDIR: - result = sshp ? sftp_readdir(data, sshc, sshp, block) : - CURLE_FAILED_INIT; - if(result) { - myssh_to(data, sshc, SSH_SFTP_CLOSE); - } + result = ssh_state_sftp_readdir(data, sshc, sshp, block); break; case SSH_SFTP_READDIR_LINK: - result = sshp ? ssh_state_sftp_readdir_link(data, sshc, sshp) : - CURLE_FAILED_INIT; + result = ssh_state_sftp_readdir_link(data, sshc, sshp); break; case SSH_SFTP_READDIR_BOTTOM: - if(!sshp) { - result = CURLE_FAILED_INIT; - break; - } - result = curlx_dyn_addn(&sshp->readdir, "\n", 1); - if(!result) - result = Curl_client_write(data, CLIENTWRITE_BODY, - curlx_dyn_ptr(&sshp->readdir), - curlx_dyn_len(&sshp->readdir)); - - if(result) { - curlx_dyn_free(&sshp->readdir); - myssh_to(data, sshc, SSH_STOP); - } - else { - curlx_dyn_reset(&sshp->readdir); - myssh_to(data, sshc, SSH_SFTP_READDIR); - } + result = ssh_state_sftp_readdir_bottom(data, sshc, sshp); break; case SSH_SFTP_READDIR_DONE: - if(libssh2_sftp_closedir(sshc->sftp_handle) == LIBSSH2_ERROR_EAGAIN) - result = CURLE_AGAIN; - else { - sshc->sftp_handle = NULL; - - /* no data to transfer */ - Curl_xfer_setup_nop(data); - myssh_to(data, sshc, SSH_STOP); - } + result = ssh_state_sftp_readdir_done(data, sshc); break; case SSH_SFTP_DOWNLOAD_INIT: - result = sshp ? ssh_state_sftp_download_init(data, sshc, sshp) : - CURLE_FAILED_INIT; + result = ssh_state_sftp_download_init(data, sshc, sshp); break; case SSH_SFTP_DOWNLOAD_STAT: - result = sshp ? sftp_download_stat(data, sshc, sshp, block) : - CURLE_FAILED_INIT; - if(result) { - myssh_to(data, sshc, SSH_SFTP_CLOSE); - sshc->nextstate = SSH_NO_STATE; - } + result = ssh_state_sftp_download_stat(data, sshc, sshp, block); break; case SSH_SFTP_CLOSE: - result = sshp ? ssh_state_sftp_close(data, sshc, sshp) : - CURLE_FAILED_INIT; + result = ssh_state_sftp_close(data, sshc, sshp); break; case SSH_SFTP_SHUTDOWN: @@ -2864,114 +3105,35 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, break; case SSH_SCP_TRANS_INIT: - result = sshp ? Curl_getworkingpath(data, sshc->homedir, &sshp->path) : - CURLE_FAILED_INIT; - if(result) { - myssh_to(data, sshc, SSH_STOP); - break; - } - - if(data->state.upload) { - if(data->state.infilesize < 0) { - failf(data, "SCP requires a known file size for upload"); - result = CURLE_UPLOAD_FAILED; - myssh_to(data, sshc, SSH_SCP_CHANNEL_FREE); - break; - } - myssh_to(data, sshc, SSH_SCP_UPLOAD_INIT); - } - else { - myssh_to(data, sshc, SSH_SCP_DOWNLOAD_INIT); - } + result = ssh_state_scp_trans_init(data, sshc, sshp); break; case SSH_SCP_UPLOAD_INIT: - result = sshp ? ssh_state_scp_upload_init(data, sshc, sshp) : - CURLE_FAILED_INIT; + result = ssh_state_scp_upload_init(data, sshc, sshp); break; case SSH_SCP_DOWNLOAD_INIT: - result = sshp ? ssh_state_scp_download_init(data, sshc, sshp) : - CURLE_FAILED_INIT; + result = ssh_state_scp_download_init(data, sshc, sshp); break; case SSH_SCP_DONE: - if(data->state.upload) - myssh_to(data, sshc, SSH_SCP_SEND_EOF); - else - myssh_to(data, sshc, SSH_SCP_CHANNEL_FREE); + result = ssh_state_scp_done(data, sshc); break; case SSH_SCP_SEND_EOF: - if(sshc->ssh_channel) { - int rc = libssh2_channel_send_eof(sshc->ssh_channel); - if(rc == LIBSSH2_ERROR_EAGAIN) { - result = CURLE_AGAIN; - break; - } - if(rc) { - char *err_msg = NULL; - (void)libssh2_session_last_error(sshc->ssh_session, - &err_msg, NULL, 0); - infof(data, "Failed to send libssh2 channel EOF: %d %s", - rc, err_msg); - } - } - myssh_to(data, sshc, SSH_SCP_WAIT_EOF); + result = ssh_state_scp_send_eof(data, sshc); break; case SSH_SCP_WAIT_EOF: - if(sshc->ssh_channel) { - int rc = libssh2_channel_wait_eof(sshc->ssh_channel); - if(rc == LIBSSH2_ERROR_EAGAIN) { - result = CURLE_AGAIN; - break; - } - if(rc) { - char *err_msg = NULL; - (void)libssh2_session_last_error(sshc->ssh_session, - &err_msg, NULL, 0); - infof(data, "Failed to get channel EOF: %d %s", rc, err_msg); - } - } - myssh_to(data, sshc, SSH_SCP_WAIT_CLOSE); + result = ssh_state_scp_wait_eof(data, sshc); break; case SSH_SCP_WAIT_CLOSE: - if(sshc->ssh_channel) { - int rc = libssh2_channel_wait_closed(sshc->ssh_channel); - if(rc == LIBSSH2_ERROR_EAGAIN) { - result = CURLE_AGAIN; - break; - } - if(rc) { - char *err_msg = NULL; - (void)libssh2_session_last_error(sshc->ssh_session, - &err_msg, NULL, 0); - infof(data, "Channel failed to close: %d %s", rc, err_msg); - } - } - myssh_to(data, sshc, SSH_SCP_CHANNEL_FREE); + result = ssh_state_scp_wait_close(data, sshc); break; case SSH_SCP_CHANNEL_FREE: - if(sshc->ssh_channel) { - int rc = libssh2_channel_free(sshc->ssh_channel); - if(rc == LIBSSH2_ERROR_EAGAIN) { - result = CURLE_AGAIN; - break; - } - if(rc < 0) { - char *err_msg = NULL; - (void)libssh2_session_last_error(sshc->ssh_session, - &err_msg, NULL, 0); - infof(data, "Failed to free libssh2 scp subsystem: %d %s", - rc, err_msg); - } - sshc->ssh_channel = NULL; - } - CURL_TRC_SSH(data, "SCP DONE phase complete"); - myssh_to(data, sshc, SSH_STOP); + result = ssh_state_scp_channel_free(data, sshc); break; case SSH_SESSION_DISCONNECT: @@ -2979,14 +3141,7 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, break; case SSH_SESSION_FREE: - result = sshc_cleanup(sshc, data, FALSE); - if(result) - break; - /* the code we are about to return */ - memset(sshc, 0, sizeof(struct ssh_conn)); - connclose(conn, "SSH session free"); - sshc->state = SSH_SESSION_FREE; /* current */ - myssh_to(data, sshc, SSH_STOP); + result = ssh_state_session_free(data, sshc); break; case SSH_QUIT: