← Commit list

a20989b82c

Daniel Stenberg
Daniel Stenberg
2026-04-07
SUCCESS Duration: 245s

Subject

libssh2: split ssh_statemachine into more sub functions

Binary

No binary (build failed)

Architecture & Compiler Flags

Architecture: x86_64-linux-gnu Compiler: gcc (Ubuntu 11.4.0-1ubuntu1~22.04.3) 11.4.0

—

Build Log

(log yok)

Commit Diff GitHub →

lib/vssh/libssh2.c+397 -242
@@ -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: