1
0
mirror of https://github.com/moparisthebest/curl synced 2024-12-23 16:48:49 -05:00

libssh2: move data from connection object to transfer object

Readdir data, filenames and attributes are strictly related to the
transfer and not the connection. This also reduces the total size of the
fixed connectdata struct.

Closes #6519
This commit is contained in:
Daniel Stenberg 2021-01-25 10:44:30 +01:00
parent abfb0b57bc
commit 2dcc940959
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
2 changed files with 149 additions and 139 deletions

View File

@ -767,8 +767,8 @@ static CURLcode ssh_force_knownhost_key_type(struct Curl_easy *data)
infof(data, "Set \"%s\" as SSH hostkey type\n", hostkey_method); infof(data, "Set \"%s\" as SSH hostkey type\n", hostkey_method);
result = libssh2_session_error_to_CURLE( result = libssh2_session_error_to_CURLE(
libssh2_session_method_pref( libssh2_session_method_pref(
sshc->ssh_session, LIBSSH2_METHOD_HOSTKEY, hostkey_method)); sshc->ssh_session, LIBSSH2_METHOD_HOSTKEY, hostkey_method));
} }
else { else {
infof(data, "Did not find host %s in %s\n", infof(data, "Did not find host %s in %s\n",
@ -792,7 +792,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
{ {
CURLcode result = CURLE_OK; CURLcode result = CURLE_OK;
struct connectdata *conn = data->conn; struct connectdata *conn = data->conn;
struct SSHPROTO *sftp_scp = data->req.p.ssh; struct SSHPROTO *sshp = data->req.p.ssh;
struct ssh_conn *sshc = &conn->proto.sshc; struct ssh_conn *sshc = &conn->proto.sshc;
curl_socket_t sock = conn->sock[FIRSTSOCKET]; curl_socket_t sock = conn->sock[FIRSTSOCKET];
int rc = LIBSSH2_ERROR_NONE; int rc = LIBSSH2_ERROR_NONE;
@ -803,7 +803,6 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
*block = 0; /* we're not blocking by default */ *block = 0; /* we're not blocking by default */
do { do {
switch(sshc->state) { switch(sshc->state) {
case SSH_INIT: case SSH_INIT:
sshc->secondCreateDirs = 0; sshc->secondCreateDirs = 0;
@ -1275,7 +1274,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
case SSH_SFTP_QUOTE_INIT: case SSH_SFTP_QUOTE_INIT:
result = Curl_getworkingpath(data, sshc->homedir, &sftp_scp->path); result = Curl_getworkingpath(data, sshc->homedir, &sshp->path);
if(result) { if(result) {
sshc->actualcode = result; sshc->actualcode = result;
state(data, SSH_STOP); state(data, SSH_STOP);
@ -1330,7 +1329,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
if(strcasecompare("pwd", cmd)) { if(strcasecompare("pwd", cmd)) {
/* output debug output if that is requested */ /* output debug output if that is requested */
char *tmp = aprintf("257 \"%s\" is current directory.\n", char *tmp = aprintf("257 \"%s\" is current directory.\n",
sftp_scp->path); sshp->path);
if(!tmp) { if(!tmp) {
result = CURLE_OUT_OF_MEMORY; result = CURLE_OUT_OF_MEMORY;
state(data, SSH_SFTP_CLOSE); state(data, SSH_SFTP_CLOSE);
@ -1412,7 +1411,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
sshc->actualcode = result; sshc->actualcode = result;
break; break;
} }
memset(&sshc->quote_attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES)); memset(&sshp->quote_attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES));
state(data, SSH_SFTP_QUOTE_STAT); state(data, SSH_SFTP_QUOTE_STAT);
break; break;
} }
@ -1531,7 +1530,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshc->quote_path2, rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshc->quote_path2,
curlx_uztoui(strlen(sshc->quote_path2)), curlx_uztoui(strlen(sshc->quote_path2)),
LIBSSH2_SFTP_STAT, LIBSSH2_SFTP_STAT,
&sshc->quote_attrs); &sshp->quote_attrs);
if(rc == LIBSSH2_ERROR_EAGAIN) { if(rc == LIBSSH2_ERROR_EAGAIN) {
break; break;
} }
@ -1550,9 +1549,9 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
/* Now set the new attributes... */ /* Now set the new attributes... */
if(strncasecompare(cmd, "chgrp", 5)) { if(strncasecompare(cmd, "chgrp", 5)) {
sshc->quote_attrs.gid = strtoul(sshc->quote_path1, NULL, 10); sshp->quote_attrs.gid = strtoul(sshc->quote_path1, NULL, 10);
sshc->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID; sshp->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID;
if(sshc->quote_attrs.gid == 0 && !ISDIGIT(sshc->quote_path1[0]) && if(sshp->quote_attrs.gid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
!sshc->acceptfail) { !sshc->acceptfail) {
Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path1);
Curl_safefree(sshc->quote_path2); Curl_safefree(sshc->quote_path2);
@ -1564,10 +1563,10 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
} }
} }
else if(strncasecompare(cmd, "chmod", 5)) { else if(strncasecompare(cmd, "chmod", 5)) {
sshc->quote_attrs.permissions = strtoul(sshc->quote_path1, NULL, 8); sshp->quote_attrs.permissions = strtoul(sshc->quote_path1, NULL, 8);
sshc->quote_attrs.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS; sshp->quote_attrs.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS;
/* permissions are octal */ /* permissions are octal */
if(sshc->quote_attrs.permissions == 0 && if(sshp->quote_attrs.permissions == 0 &&
!ISDIGIT(sshc->quote_path1[0])) { !ISDIGIT(sshc->quote_path1[0])) {
Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path1);
Curl_safefree(sshc->quote_path2); Curl_safefree(sshc->quote_path2);
@ -1579,9 +1578,9 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
} }
} }
else if(strncasecompare(cmd, "chown", 5)) { else if(strncasecompare(cmd, "chown", 5)) {
sshc->quote_attrs.uid = strtoul(sshc->quote_path1, NULL, 10); sshp->quote_attrs.uid = strtoul(sshc->quote_path1, NULL, 10);
sshc->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID; sshp->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID;
if(sshc->quote_attrs.uid == 0 && !ISDIGIT(sshc->quote_path1[0]) && if(sshp->quote_attrs.uid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
!sshc->acceptfail) { !sshc->acceptfail) {
Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path1);
Curl_safefree(sshc->quote_path2); Curl_safefree(sshc->quote_path2);
@ -1603,8 +1602,8 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
sshc->actualcode = CURLE_QUOTE_ERROR; sshc->actualcode = CURLE_QUOTE_ERROR;
break; break;
} }
sshc->quote_attrs.atime = (unsigned long)date; sshp->quote_attrs.atime = (unsigned long)date;
sshc->quote_attrs.flags = LIBSSH2_SFTP_ATTR_ACMODTIME; sshp->quote_attrs.flags = LIBSSH2_SFTP_ATTR_ACMODTIME;
} }
else if(strncasecompare(cmd, "mtime", 5)) { else if(strncasecompare(cmd, "mtime", 5)) {
time_t date = Curl_getdate_capped(sshc->quote_path1); time_t date = Curl_getdate_capped(sshc->quote_path1);
@ -1617,8 +1616,8 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
sshc->actualcode = CURLE_QUOTE_ERROR; sshc->actualcode = CURLE_QUOTE_ERROR;
break; break;
} }
sshc->quote_attrs.mtime = (unsigned long)date; sshp->quote_attrs.mtime = (unsigned long)date;
sshc->quote_attrs.flags = LIBSSH2_SFTP_ATTR_ACMODTIME; sshp->quote_attrs.flags = LIBSSH2_SFTP_ATTR_ACMODTIME;
} }
/* Now send the completed structure... */ /* Now send the completed structure... */
@ -1630,7 +1629,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshc->quote_path2, rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshc->quote_path2,
curlx_uztoui(strlen(sshc->quote_path2)), curlx_uztoui(strlen(sshc->quote_path2)),
LIBSSH2_SFTP_SETSTAT, LIBSSH2_SFTP_SETSTAT,
&sshc->quote_attrs); &sshp->quote_attrs);
if(rc == LIBSSH2_ERROR_EAGAIN) { if(rc == LIBSSH2_ERROR_EAGAIN) {
break; break;
} }
@ -1823,8 +1822,8 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
{ {
LIBSSH2_SFTP_ATTRIBUTES attrs; LIBSSH2_SFTP_ATTRIBUTES attrs;
rc = libssh2_sftp_stat_ex(sshc->sftp_session, sftp_scp->path, rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshp->path,
curlx_uztoui(strlen(sftp_scp->path)), curlx_uztoui(strlen(sshp->path)),
LIBSSH2_SFTP_STAT, &attrs); LIBSSH2_SFTP_STAT, &attrs);
if(rc == LIBSSH2_ERROR_EAGAIN) { if(rc == LIBSSH2_ERROR_EAGAIN) {
break; break;
@ -1841,7 +1840,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
if(data->set.upload) if(data->set.upload)
state(data, SSH_SFTP_UPLOAD_INIT); state(data, SSH_SFTP_UPLOAD_INIT);
else { else {
if(sftp_scp->path[strlen(sftp_scp->path)-1] == '/') if(sshp->path[strlen(sshp->path)-1] == '/')
state(data, SSH_SFTP_READDIR_INIT); state(data, SSH_SFTP_READDIR_INIT);
else else
state(data, SSH_SFTP_DOWNLOAD_INIT); state(data, SSH_SFTP_DOWNLOAD_INIT);
@ -1861,8 +1860,8 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
if(data->state.resume_from != 0) { if(data->state.resume_from != 0) {
LIBSSH2_SFTP_ATTRIBUTES attrs; LIBSSH2_SFTP_ATTRIBUTES attrs;
if(data->state.resume_from < 0) { if(data->state.resume_from < 0) {
rc = libssh2_sftp_stat_ex(sshc->sftp_session, sftp_scp->path, rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshp->path,
curlx_uztoui(strlen(sftp_scp->path)), curlx_uztoui(strlen(sshp->path)),
LIBSSH2_SFTP_STAT, &attrs); LIBSSH2_SFTP_STAT, &attrs);
if(rc == LIBSSH2_ERROR_EAGAIN) { if(rc == LIBSSH2_ERROR_EAGAIN) {
break; break;
@ -1892,8 +1891,8 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC; flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC;
sshc->sftp_handle = sshc->sftp_handle =
libssh2_sftp_open_ex(sshc->sftp_session, sftp_scp->path, libssh2_sftp_open_ex(sshc->sftp_session, sshp->path,
curlx_uztoui(strlen(sftp_scp->path)), curlx_uztoui(strlen(sshp->path)),
flags, data->set.new_file_perms, flags, data->set.new_file_perms,
LIBSSH2_SFTP_OPENFILE); LIBSSH2_SFTP_OPENFILE);
@ -1922,7 +1921,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
(sftperr == LIBSSH2_FX_FAILURE) || (sftperr == LIBSSH2_FX_FAILURE) ||
(sftperr == LIBSSH2_FX_NO_SUCH_PATH)) && (sftperr == LIBSSH2_FX_NO_SUCH_PATH)) &&
(data->set.ftp_create_missing_dirs && (data->set.ftp_create_missing_dirs &&
(strlen(sftp_scp->path) > 1))) { (strlen(sshp->path) > 1))) {
/* try to create the path remotely */ /* try to create the path remotely */
rc = 0; /* clear rc and continue */ rc = 0; /* clear rc and continue */
sshc->secondCreateDirs = 1; sshc->secondCreateDirs = 1;
@ -2032,8 +2031,8 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
} }
case SSH_SFTP_CREATE_DIRS_INIT: case SSH_SFTP_CREATE_DIRS_INIT:
if(strlen(sftp_scp->path) > 1) { if(strlen(sshp->path) > 1) {
sshc->slash_pos = sftp_scp->path + 1; /* ignore the leading '/' */ sshc->slash_pos = sshp->path + 1; /* ignore the leading '/' */
state(data, SSH_SFTP_CREATE_DIRS); state(data, SSH_SFTP_CREATE_DIRS);
} }
else { else {
@ -2046,7 +2045,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
if(sshc->slash_pos) { if(sshc->slash_pos) {
*sshc->slash_pos = 0; *sshc->slash_pos = 0;
infof(data, "Creating directory '%s'\n", sftp_scp->path); infof(data, "Creating directory '%s'\n", sshp->path);
state(data, SSH_SFTP_CREATE_DIRS_MKDIR); state(data, SSH_SFTP_CREATE_DIRS_MKDIR);
break; break;
} }
@ -2055,8 +2054,8 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
case SSH_SFTP_CREATE_DIRS_MKDIR: case SSH_SFTP_CREATE_DIRS_MKDIR:
/* 'mode' - parameter is preliminary - default to 0644 */ /* 'mode' - parameter is preliminary - default to 0644 */
rc = libssh2_sftp_mkdir_ex(sshc->sftp_session, sftp_scp->path, rc = libssh2_sftp_mkdir_ex(sshc->sftp_session, sshp->path,
curlx_uztoui(strlen(sftp_scp->path)), curlx_uztoui(strlen(sshp->path)),
data->set.new_directory_perms); data->set.new_directory_perms);
if(rc == LIBSSH2_ERROR_EAGAIN) { if(rc == LIBSSH2_ERROR_EAGAIN) {
break; break;
@ -2095,9 +2094,9 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
* listing * listing
*/ */
sshc->sftp_handle = libssh2_sftp_open_ex(sshc->sftp_session, sshc->sftp_handle = libssh2_sftp_open_ex(sshc->sftp_session,
sftp_scp->path, sshp->path,
curlx_uztoui( curlx_uztoui(
strlen(sftp_scp->path)), strlen(sshp->path)),
0, 0, LIBSSH2_SFTP_OPENDIR); 0, 0, LIBSSH2_SFTP_OPENDIR);
if(!sshc->sftp_handle) { if(!sshc->sftp_handle) {
if(libssh2_session_last_errno(sshc->ssh_session) == if(libssh2_session_last_errno(sshc->ssh_session) ==
@ -2113,40 +2112,40 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
sshc->actualcode = result?result:CURLE_SSH; sshc->actualcode = result?result:CURLE_SSH;
break; break;
} }
sshc->readdir_filename = malloc(PATH_MAX + 1); sshp->readdir_filename = malloc(PATH_MAX + 1);
if(!sshc->readdir_filename) { if(!sshp->readdir_filename) {
state(data, SSH_SFTP_CLOSE); state(data, SSH_SFTP_CLOSE);
sshc->actualcode = CURLE_OUT_OF_MEMORY; sshc->actualcode = CURLE_OUT_OF_MEMORY;
break; break;
} }
sshc->readdir_longentry = malloc(PATH_MAX + 1); sshp->readdir_longentry = malloc(PATH_MAX + 1);
if(!sshc->readdir_longentry) { if(!sshp->readdir_longentry) {
Curl_safefree(sshc->readdir_filename); Curl_safefree(sshp->readdir_filename);
state(data, SSH_SFTP_CLOSE); state(data, SSH_SFTP_CLOSE);
sshc->actualcode = CURLE_OUT_OF_MEMORY; sshc->actualcode = CURLE_OUT_OF_MEMORY;
break; break;
} }
Curl_dyn_init(&sshc->readdir, PATH_MAX * 2); Curl_dyn_init(&sshp->readdir, PATH_MAX * 2);
state(data, SSH_SFTP_READDIR); state(data, SSH_SFTP_READDIR);
break; break;
case SSH_SFTP_READDIR: case SSH_SFTP_READDIR:
rc = libssh2_sftp_readdir_ex(sshc->sftp_handle, rc = libssh2_sftp_readdir_ex(sshc->sftp_handle,
sshc->readdir_filename, sshp->readdir_filename,
PATH_MAX, PATH_MAX,
sshc->readdir_longentry, sshp->readdir_longentry,
PATH_MAX, PATH_MAX,
&sshc->readdir_attrs); &sshp->readdir_attrs);
if(rc == LIBSSH2_ERROR_EAGAIN) { if(rc == LIBSSH2_ERROR_EAGAIN) {
break; break;
} }
if(rc > 0) { if(rc > 0) {
readdir_len = (size_t) rc; readdir_len = (size_t) rc;
sshc->readdir_filename[readdir_len] = '\0'; sshp->readdir_filename[readdir_len] = '\0';
if(data->set.ftp_list_only) { if(data->set.ftp_list_only) {
result = Curl_client_write(data, CLIENTWRITE_BODY, result = Curl_client_write(data, CLIENTWRITE_BODY,
sshc->readdir_filename, sshp->readdir_filename,
readdir_len); readdir_len);
if(!result) if(!result)
result = Curl_client_write(data, CLIENTWRITE_BODY, result = Curl_client_write(data, CLIENTWRITE_BODY,
@ -2160,19 +2159,19 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
data->req.bytecount += readdir_len + 1; data->req.bytecount += readdir_len + 1;
/* output debug output if that is requested */ /* output debug output if that is requested */
Curl_debug(data, CURLINFO_DATA_IN, sshc->readdir_filename, Curl_debug(data, CURLINFO_DATA_IN, sshp->readdir_filename,
readdir_len); readdir_len);
Curl_debug(data, CURLINFO_DATA_IN, (char *)"\n", 1); Curl_debug(data, CURLINFO_DATA_IN, (char *)"\n", 1);
} }
else { else {
result = Curl_dyn_add(&sshc->readdir, sshc->readdir_longentry); result = Curl_dyn_add(&sshp->readdir, sshp->readdir_longentry);
if(!result) { if(!result) {
if((sshc->readdir_attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) && if((sshp->readdir_attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) &&
((sshc->readdir_attrs.permissions & LIBSSH2_SFTP_S_IFMT) == ((sshp->readdir_attrs.permissions & LIBSSH2_SFTP_S_IFMT) ==
LIBSSH2_SFTP_S_IFLNK)) { LIBSSH2_SFTP_S_IFLNK)) {
Curl_dyn_init(&sshc->readdir_link, PATH_MAX); Curl_dyn_init(&sshp->readdir_link, PATH_MAX);
result = Curl_dyn_add(&sshc->readdir_link, sftp_scp->path); result = Curl_dyn_add(&sshp->readdir_link, sshp->path);
state(data, SSH_SFTP_READDIR_LINK); state(data, SSH_SFTP_READDIR_LINK);
if(!result) if(!result)
break; break;
@ -2188,8 +2187,8 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
} }
} }
else if(rc == 0) { else if(rc == 0) {
Curl_safefree(sshc->readdir_filename); Curl_safefree(sshp->readdir_filename);
Curl_safefree(sshc->readdir_longentry); Curl_safefree(sshp->readdir_longentry);
state(data, SSH_SFTP_READDIR_DONE); state(data, SSH_SFTP_READDIR_DONE);
break; break;
} }
@ -2200,8 +2199,8 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
failf(data, "Could not open remote file for reading: %s :: %d", failf(data, "Could not open remote file for reading: %s :: %d",
sftp_libssh2_strerror(sftperr), sftp_libssh2_strerror(sftperr),
libssh2_session_last_errno(sshc->ssh_session)); libssh2_session_last_errno(sshc->ssh_session));
Curl_safefree(sshc->readdir_filename); Curl_safefree(sshp->readdir_filename);
Curl_safefree(sshc->readdir_longentry); Curl_safefree(sshp->readdir_longentry);
state(data, SSH_SFTP_CLOSE); state(data, SSH_SFTP_CLOSE);
break; break;
} }
@ -2210,22 +2209,22 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
case SSH_SFTP_READDIR_LINK: case SSH_SFTP_READDIR_LINK:
rc = rc =
libssh2_sftp_symlink_ex(sshc->sftp_session, libssh2_sftp_symlink_ex(sshc->sftp_session,
Curl_dyn_ptr(&sshc->readdir_link), Curl_dyn_ptr(&sshp->readdir_link),
(int)Curl_dyn_len(&sshc->readdir_link), (int)Curl_dyn_len(&sshp->readdir_link),
sshc->readdir_filename, sshp->readdir_filename,
PATH_MAX, LIBSSH2_SFTP_READLINK); PATH_MAX, LIBSSH2_SFTP_READLINK);
if(rc == LIBSSH2_ERROR_EAGAIN) { if(rc == LIBSSH2_ERROR_EAGAIN) {
break; break;
} }
Curl_dyn_free(&sshc->readdir_link); Curl_dyn_free(&sshp->readdir_link);
/* append filename and extra output */ /* append filename and extra output */
result = Curl_dyn_addf(&sshc->readdir, " -> %s", sshc->readdir_filename); result = Curl_dyn_addf(&sshp->readdir, " -> %s", sshp->readdir_filename);
if(result) { if(result) {
sshc->readdir_line = NULL; sshc->readdir_line = NULL;
Curl_safefree(sshc->readdir_filename); Curl_safefree(sshp->readdir_filename);
Curl_safefree(sshc->readdir_longentry); Curl_safefree(sshp->readdir_longentry);
state(data, SSH_SFTP_CLOSE); state(data, SSH_SFTP_CLOSE);
sshc->actualcode = result; sshc->actualcode = result;
break; break;
@ -2235,25 +2234,25 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
break; break;
case SSH_SFTP_READDIR_BOTTOM: case SSH_SFTP_READDIR_BOTTOM:
result = Curl_dyn_addn(&sshc->readdir, "\n", 1); result = Curl_dyn_addn(&sshp->readdir, "\n", 1);
if(!result) if(!result)
result = Curl_client_write(data, CLIENTWRITE_BODY, result = Curl_client_write(data, CLIENTWRITE_BODY,
Curl_dyn_ptr(&sshc->readdir), Curl_dyn_ptr(&sshp->readdir),
Curl_dyn_len(&sshc->readdir)); Curl_dyn_len(&sshp->readdir));
if(!result) { if(!result) {
/* output debug output if that is requested */ /* output debug output if that is requested */
Curl_debug(data, CURLINFO_DATA_IN, Curl_debug(data, CURLINFO_DATA_IN,
Curl_dyn_ptr(&sshc->readdir), Curl_dyn_ptr(&sshp->readdir),
Curl_dyn_len(&sshc->readdir)); Curl_dyn_len(&sshp->readdir));
data->req.bytecount += Curl_dyn_len(&sshc->readdir); data->req.bytecount += Curl_dyn_len(&sshp->readdir);
} }
if(result) { if(result) {
Curl_dyn_free(&sshc->readdir); Curl_dyn_free(&sshp->readdir);
state(data, SSH_STOP); state(data, SSH_STOP);
} }
else { else {
Curl_dyn_reset(&sshc->readdir); Curl_dyn_reset(&sshp->readdir);
state(data, SSH_SFTP_READDIR); state(data, SSH_SFTP_READDIR);
} }
break; break;
@ -2265,8 +2264,8 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
break; break;
} }
sshc->sftp_handle = NULL; sshc->sftp_handle = NULL;
Curl_safefree(sshc->readdir_filename); Curl_safefree(sshp->readdir_filename);
Curl_safefree(sshc->readdir_longentry); Curl_safefree(sshp->readdir_longentry);
/* no data to transfer */ /* no data to transfer */
Curl_setup_transfer(data, -1, -1, FALSE, -1); Curl_setup_transfer(data, -1, -1, FALSE, -1);
@ -2278,8 +2277,8 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
* Work on getting the specified file * Work on getting the specified file
*/ */
sshc->sftp_handle = sshc->sftp_handle =
libssh2_sftp_open_ex(sshc->sftp_session, sftp_scp->path, libssh2_sftp_open_ex(sshc->sftp_session, sshp->path,
curlx_uztoui(strlen(sftp_scp->path)), curlx_uztoui(strlen(sshp->path)),
LIBSSH2_FXF_READ, data->set.new_file_perms, LIBSSH2_FXF_READ, data->set.new_file_perms,
LIBSSH2_SFTP_OPENFILE); LIBSSH2_SFTP_OPENFILE);
if(!sshc->sftp_handle) { if(!sshc->sftp_handle) {
@ -2303,8 +2302,8 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
{ {
LIBSSH2_SFTP_ATTRIBUTES attrs; LIBSSH2_SFTP_ATTRIBUTES attrs;
rc = libssh2_sftp_stat_ex(sshc->sftp_session, sftp_scp->path, rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshp->path,
curlx_uztoui(strlen(sftp_scp->path)), curlx_uztoui(strlen(sshp->path)),
LIBSSH2_SFTP_STAT, &attrs); LIBSSH2_SFTP_STAT, &attrs);
if(rc == LIBSSH2_ERROR_EAGAIN) { if(rc == LIBSSH2_ERROR_EAGAIN) {
break; break;
@ -2367,7 +2366,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
size = to - from + 1; size = to - from + 1;
} }
SFTP_SEEK(conn->proto.sshc.sftp_handle, from); SFTP_SEEK(sshc->sftp_handle, from);
} }
data->req.size = size; data->req.size = size;
data->req.maxdownload = size; data->req.maxdownload = size;
@ -2449,7 +2448,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
sshc->sftp_handle = NULL; sshc->sftp_handle = NULL;
} }
Curl_safefree(sftp_scp->path); Curl_safefree(sshp->path);
DEBUGF(infof(data, "SFTP DONE done\n")); DEBUGF(infof(data, "SFTP DONE done\n"));
@ -2503,7 +2502,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
break; break;
case SSH_SCP_TRANS_INIT: case SSH_SCP_TRANS_INIT:
result = Curl_getworkingpath(data, sshc->homedir, &sftp_scp->path); result = Curl_getworkingpath(data, sshc->homedir, &sshp->path);
if(result) { if(result) {
sshc->actualcode = result; sshc->actualcode = result;
state(data, SSH_STOP); state(data, SSH_STOP);
@ -2532,7 +2531,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
* directory in the path. * directory in the path.
*/ */
sshc->ssh_channel = sshc->ssh_channel =
SCP_SEND(sshc->ssh_session, sftp_scp->path, data->set.new_file_perms, SCP_SEND(sshc->ssh_session, sshp->path, data->set.new_file_perms,
data->state.infilesize); data->state.infilesize);
if(!sshc->ssh_channel) { if(!sshc->ssh_channel) {
int ssh_err; int ssh_err;
@ -2600,12 +2599,12 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
struct stat sb; struct stat sb;
memset(&sb, 0, sizeof(struct stat)); memset(&sb, 0, sizeof(struct stat));
sshc->ssh_channel = libssh2_scp_recv(sshc->ssh_session, sshc->ssh_channel = libssh2_scp_recv(sshc->ssh_session,
sftp_scp->path, &sb); sshp->path, &sb);
#else #else
libssh2_struct_stat sb; libssh2_struct_stat sb;
memset(&sb, 0, sizeof(libssh2_struct_stat)); memset(&sb, 0, sizeof(libssh2_struct_stat));
sshc->ssh_channel = libssh2_scp_recv2(sshc->ssh_session, sshc->ssh_channel = libssh2_scp_recv2(sshc->ssh_session,
sftp_scp->path, &sb); sshp->path, &sb);
#endif #endif
if(!sshc->ssh_channel) { if(!sshc->ssh_channel) {
@ -2832,11 +2831,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
Curl_safefree(sshc->quote_path2); Curl_safefree(sshc->quote_path2);
Curl_safefree(sshc->homedir); Curl_safefree(sshc->homedir);
Curl_safefree(sshc->readdir_filename);
Curl_safefree(sshc->readdir_longentry);
Curl_safefree(sshc->readdir_line); Curl_safefree(sshc->readdir_line);
Curl_dyn_free(&sshc->readdir);
/* the code we are about to return */ /* the code we are about to return */
result = sshc->actualcode; result = sshc->actualcode;
@ -2896,8 +2891,9 @@ static int ssh_getsock(struct Curl_easy *data,
* function in all cases so that when it _doesn't_ return EAGAIN we can * function in all cases so that when it _doesn't_ return EAGAIN we can
* restore the default wait bits. * restore the default wait bits.
*/ */
static void ssh_block2waitfor(struct connectdata *conn, bool block) static void ssh_block2waitfor(struct Curl_easy *data, bool block)
{ {
struct connectdata *conn = data->conn;
struct ssh_conn *sshc = &conn->proto.sshc; struct ssh_conn *sshc = &conn->proto.sshc;
int dir = 0; int dir = 0;
if(block) { if(block) {
@ -2928,15 +2924,15 @@ static CURLcode ssh_multi_statemach(struct Curl_easy *data, bool *done)
/* if there's no error, it isn't done and it didn't EWOULDBLOCK, then /* if there's no error, it isn't done and it didn't EWOULDBLOCK, then
try again */ try again */
} while(!result && !*done && !block); } while(!result && !*done && !block);
ssh_block2waitfor(conn, block); ssh_block2waitfor(data, block);
return result; return result;
} }
static CURLcode ssh_block_statemach(struct Curl_easy *data, static CURLcode ssh_block_statemach(struct Curl_easy *data,
bool duringconnect) struct connectdata *conn,
bool duringconnect)
{ {
struct connectdata *conn = data->conn;
struct ssh_conn *sshc = &conn->proto.sshc; struct ssh_conn *sshc = &conn->proto.sshc;
CURLcode result = CURLE_OK; CURLcode result = CURLE_OK;
@ -3058,19 +3054,24 @@ static CURLcode ssh_connect(struct Curl_easy *data, bool *done)
#ifdef CURL_LIBSSH2_DEBUG #ifdef CURL_LIBSSH2_DEBUG
curl_socket_t sock; curl_socket_t sock;
#endif #endif
struct ssh_conn *ssh; struct SSHPROTO *sshp = data->req.p.ssh;
struct ssh_conn *sshc;
CURLcode result; CURLcode result;
struct connectdata *conn = data->conn; struct connectdata *conn = data->conn;
/* initialize per-handle data if not already */ /* initialize per-handle data if not already */
if(!data->req.p.ssh) if(!sshp) {
ssh_setup_connection(data, conn); result = ssh_setup_connection(data, conn);
if(result)
return result;
sshp = data->req.p.ssh;
}
/* We default to persistent connections. We set this already in this connect /* We default to persistent connections. We set this already in this connect
function to make the re-use checks properly be able to check this bit. */ function to make the re-use checks properly be able to check this bit. */
connkeep(conn, "SSH default"); connkeep(conn, "SSH default");
ssh = &conn->proto.sshc; sshc = &conn->proto.sshc;
#ifdef CURL_LIBSSH2_DEBUG #ifdef CURL_LIBSSH2_DEBUG
if(conn->user) { if(conn->user) {
@ -3082,10 +3083,10 @@ static CURLcode ssh_connect(struct Curl_easy *data, bool *done)
sock = conn->sock[FIRSTSOCKET]; sock = conn->sock[FIRSTSOCKET];
#endif /* CURL_LIBSSH2_DEBUG */ #endif /* CURL_LIBSSH2_DEBUG */
ssh->ssh_session = libssh2_session_init_ex(my_libssh2_malloc, sshc->ssh_session = libssh2_session_init_ex(my_libssh2_malloc,
my_libssh2_free, my_libssh2_free,
my_libssh2_realloc, data); my_libssh2_realloc, data);
if(ssh->ssh_session == NULL) { if(sshc->ssh_session == NULL) {
failf(data, "Failure initialising ssh session"); failf(data, "Failure initialising ssh session");
return CURLE_FAILED_INIT; return CURLE_FAILED_INIT;
} }
@ -3124,15 +3125,15 @@ static CURLcode ssh_connect(struct Curl_easy *data, bool *done)
int flags, void **abstract); int flags, void **abstract);
*/ */
libssh2_session_callback_set(ssh->ssh_session, libssh2_session_callback_set(sshc->ssh_session,
LIBSSH2_CALLBACK_RECV, sshrecv.recvp); LIBSSH2_CALLBACK_RECV, sshrecv.recvp);
libssh2_session_callback_set(ssh->ssh_session, libssh2_session_callback_set(sshc->ssh_session,
LIBSSH2_CALLBACK_SEND, sshsend.sendp); LIBSSH2_CALLBACK_SEND, sshsend.sendp);
/* Store the underlying TLS recv/send function pointers to be used when /* Store the underlying TLS recv/send function pointers to be used when
reading from the proxy */ reading from the proxy */
ssh->tls_recv = conn->recv[FIRSTSOCKET]; sshc->tls_recv = conn->recv[FIRSTSOCKET];
ssh->tls_send = conn->send[FIRSTSOCKET]; sshc->tls_send = conn->send[FIRSTSOCKET];
} }
#endif /* CURL_DISABLE_PROXY */ #endif /* CURL_DISABLE_PROXY */
@ -3147,7 +3148,7 @@ static CURLcode ssh_connect(struct Curl_easy *data, bool *done)
if(data->set.ssh_compression) { if(data->set.ssh_compression) {
#if LIBSSH2_VERSION_NUM >= 0x010208 #if LIBSSH2_VERSION_NUM >= 0x010208
if(libssh2_session_flag(ssh->ssh_session, LIBSSH2_FLAG_COMPRESS, 1) < 0) if(libssh2_session_flag(sshc->ssh_session, LIBSSH2_FLAG_COMPRESS, 1) < 0)
#endif #endif
infof(data, "Failed to enable compression for ssh session\n"); infof(data, "Failed to enable compression for ssh session\n");
} }
@ -3155,14 +3156,14 @@ static CURLcode ssh_connect(struct Curl_easy *data, bool *done)
#ifdef HAVE_LIBSSH2_KNOWNHOST_API #ifdef HAVE_LIBSSH2_KNOWNHOST_API
if(data->set.str[STRING_SSH_KNOWNHOSTS]) { if(data->set.str[STRING_SSH_KNOWNHOSTS]) {
int rc; int rc;
ssh->kh = libssh2_knownhost_init(ssh->ssh_session); sshc->kh = libssh2_knownhost_init(sshc->ssh_session);
if(!ssh->kh) { if(!sshc->kh) {
libssh2_session_free(ssh->ssh_session); libssh2_session_free(sshc->ssh_session);
return CURLE_FAILED_INIT; return CURLE_FAILED_INIT;
} }
/* read all known hosts from there */ /* read all known hosts from there */
rc = libssh2_knownhost_readfile(ssh->kh, rc = libssh2_knownhost_readfile(sshc->kh,
data->set.str[STRING_SSH_KNOWNHOSTS], data->set.str[STRING_SSH_KNOWNHOSTS],
LIBSSH2_KNOWNHOST_FILE_OPENSSH); LIBSSH2_KNOWNHOST_FILE_OPENSSH);
if(rc < 0) if(rc < 0)
@ -3273,15 +3274,15 @@ static CURLcode scp_disconnect(struct Curl_easy *data,
bool dead_connection) bool dead_connection)
{ {
CURLcode result = CURLE_OK; CURLcode result = CURLE_OK;
struct ssh_conn *ssh = &conn->proto.sshc; struct ssh_conn *sshc = &conn->proto.sshc;
(void) dead_connection; (void) dead_connection;
if(ssh->ssh_session) { if(sshc->ssh_session) {
/* only if there's a session still around to use! */ /* only if there's a session still around to use! */
state(data, SSH_SESSION_DISCONNECT); state(data, SSH_SESSION_DISCONNECT);
result = ssh_block_statemach(data, FALSE); result = ssh_block_statemach(data, conn, FALSE);
} }
return result; return result;
@ -3292,17 +3293,21 @@ static CURLcode scp_disconnect(struct Curl_easy *data,
static CURLcode ssh_done(struct Curl_easy *data, CURLcode status) static CURLcode ssh_done(struct Curl_easy *data, CURLcode status)
{ {
CURLcode result = CURLE_OK; CURLcode result = CURLE_OK;
struct SSHPROTO *sftp_scp = data->req.p.ssh; struct SSHPROTO *sshp = data->req.p.ssh;
struct connectdata *conn = data->conn;
if(!status) { if(!status) {
/* run the state-machine */ /* run the state-machine */
result = ssh_block_statemach(data, FALSE); result = ssh_block_statemach(data, conn, FALSE);
} }
else else
result = status; result = status;
if(sftp_scp) Curl_safefree(sshp->path);
Curl_safefree(sftp_scp->path); Curl_safefree(sshp->readdir_filename);
Curl_safefree(sshp->readdir_longentry);
Curl_dyn_free(&sshp->readdir);
if(Curl_pgrsDone(data)) if(Curl_pgrsDone(data))
return CURLE_ABORTED_BY_CALLBACK; return CURLE_ABORTED_BY_CALLBACK;
@ -3328,13 +3333,13 @@ static ssize_t scp_send(struct Curl_easy *data, int sockindex,
{ {
ssize_t nwrite; ssize_t nwrite;
struct connectdata *conn = data->conn; struct connectdata *conn = data->conn;
struct ssh_conn *sshc = &conn->proto.sshc;
(void)sockindex; /* we only support SCP on the fixed known primary socket */ (void)sockindex; /* we only support SCP on the fixed known primary socket */
/* libssh2_channel_write() returns int! */ /* libssh2_channel_write() returns int! */
nwrite = (ssize_t) nwrite = (ssize_t) libssh2_channel_write(sshc->ssh_channel, mem, len);
libssh2_channel_write(conn->proto.sshc.ssh_channel, mem, len);
ssh_block2waitfor(conn, (nwrite == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE); ssh_block2waitfor(data, (nwrite == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE);
if(nwrite == LIBSSH2_ERROR_EAGAIN) { if(nwrite == LIBSSH2_ERROR_EAGAIN) {
*err = CURLE_AGAIN; *err = CURLE_AGAIN;
@ -3353,13 +3358,13 @@ static ssize_t scp_recv(struct Curl_easy *data, int sockindex,
{ {
ssize_t nread; ssize_t nread;
struct connectdata *conn = data->conn; struct connectdata *conn = data->conn;
struct ssh_conn *sshc = &conn->proto.sshc;
(void)sockindex; /* we only support SCP on the fixed known primary socket */ (void)sockindex; /* we only support SCP on the fixed known primary socket */
/* libssh2_channel_read() returns int */ /* libssh2_channel_read() returns int */
nread = (ssize_t) nread = (ssize_t) libssh2_channel_read(sshc->ssh_channel, mem, len);
libssh2_channel_read(conn->proto.sshc.ssh_channel, mem, len);
ssh_block2waitfor(conn, (nread == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE); ssh_block2waitfor(data, (nread == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE);
if(nread == LIBSSH2_ERROR_EAGAIN) { if(nread == LIBSSH2_ERROR_EAGAIN) {
*err = CURLE_AGAIN; *err = CURLE_AGAIN;
nread = -1; nread = -1;
@ -3426,14 +3431,15 @@ static CURLcode sftp_disconnect(struct Curl_easy *data,
struct connectdata *conn, bool dead_connection) struct connectdata *conn, bool dead_connection)
{ {
CURLcode result = CURLE_OK; CURLcode result = CURLE_OK;
struct ssh_conn *sshc = &conn->proto.sshc;
(void) dead_connection; (void) dead_connection;
DEBUGF(infof(data, "SSH DISCONNECT starts now\n")); DEBUGF(infof(data, "SSH DISCONNECT starts now\n"));
if(conn->proto.sshc.ssh_session) { if(sshc->ssh_session) {
/* only if there's a session still around to use! */ /* only if there's a session still around to use! */
state(data, SSH_SFTP_SHUTDOWN); state(data, SSH_SFTP_SHUTDOWN);
result = ssh_block_statemach(data, FALSE); result = ssh_block_statemach(data, conn, FALSE);
} }
DEBUGF(infof(data, "SSH DISCONNECT is done\n")); DEBUGF(infof(data, "SSH DISCONNECT is done\n"));
@ -3465,11 +3471,12 @@ static ssize_t sftp_send(struct Curl_easy *data, int sockindex,
{ {
ssize_t nwrite; ssize_t nwrite;
struct connectdata *conn = data->conn; struct connectdata *conn = data->conn;
struct ssh_conn *sshc = &conn->proto.sshc;
(void)sockindex; (void)sockindex;
nwrite = libssh2_sftp_write(conn->proto.sshc.sftp_handle, mem, len); nwrite = libssh2_sftp_write(sshc->sftp_handle, mem, len);
ssh_block2waitfor(conn, (nwrite == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE); ssh_block2waitfor(data, (nwrite == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE);
if(nwrite == LIBSSH2_ERROR_EAGAIN) { if(nwrite == LIBSSH2_ERROR_EAGAIN) {
*err = CURLE_AGAIN; *err = CURLE_AGAIN;
@ -3492,11 +3499,12 @@ static ssize_t sftp_recv(struct Curl_easy *data, int sockindex,
{ {
ssize_t nread; ssize_t nread;
struct connectdata *conn = data->conn; struct connectdata *conn = data->conn;
struct ssh_conn *sshc = &conn->proto.sshc;
(void)sockindex; (void)sockindex;
nread = libssh2_sftp_read(conn->proto.sshc.sftp_handle, mem, len); nread = libssh2_sftp_read(sshc->sftp_handle, mem, len);
ssh_block2waitfor(conn, (nread == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE); ssh_block2waitfor(data, (nread == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE);
if(nread == LIBSSH2_ERROR_EAGAIN) { if(nread == LIBSSH2_ERROR_EAGAIN) {
*err = CURLE_AGAIN; *err = CURLE_AGAIN;

View File

@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____| * \___|\___/|_| \_\_____|
* *
* Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al. * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
* *
* This software is licensed as described in the file COPYING, which * This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms * you should have received as part of this distribution. The terms
@ -111,6 +111,17 @@ typedef enum {
struct. */ struct. */
struct SSHPROTO { struct SSHPROTO {
char *path; /* the path we operate on */ char *path; /* the path we operate on */
#ifdef USE_LIBSSH2
struct dynbuf readdir_link;
struct dynbuf readdir;
char *readdir_filename;
char *readdir_longentry;
LIBSSH2_SFTP_ATTRIBUTES quote_attrs; /* used by the SFTP_QUOTE state */
/* Here's a set of struct members used by the SFTP_READDIR state */
LIBSSH2_SFTP_ATTRIBUTES readdir_attrs;
#endif
}; };
/* ssh_conn is used for struct connection-oriented data in the connectdata /* ssh_conn is used for struct connection-oriented data in the connectdata
@ -167,15 +178,6 @@ struct ssh_conn {
const char *readdir_longentry; const char *readdir_longentry;
char *readdir_tmp; char *readdir_tmp;
#elif defined(USE_LIBSSH2) #elif defined(USE_LIBSSH2)
struct dynbuf readdir_link;
struct dynbuf readdir;
char *readdir_filename;
char *readdir_longentry;
LIBSSH2_SFTP_ATTRIBUTES quote_attrs; /* used by the SFTP_QUOTE state */
/* Here's a set of struct members used by the SFTP_READDIR state */
LIBSSH2_SFTP_ATTRIBUTES readdir_attrs;
LIBSSH2_SESSION *ssh_session; /* Secure Shell session */ LIBSSH2_SESSION *ssh_session; /* Secure Shell session */
LIBSSH2_CHANNEL *ssh_channel; /* Secure Shell channel handle */ LIBSSH2_CHANNEL *ssh_channel; /* Secure Shell channel handle */
LIBSSH2_SFTP *sftp_session; /* SFTP handle */ LIBSSH2_SFTP *sftp_session; /* SFTP handle */