Newer
Older
*/
James Housley
committed
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
/*
***********************************************************************
*
* sftp_perform()
*
* This is the actual DO function for SFTP. Get a file/directory according to
* the options previously setup.
*/
static
CURLcode sftp_perform(struct connectdata *conn,
bool *connected,
bool *dophase_done)
{
CURLcode result = CURLE_OK;
DEBUGF(infof(conn->data, "DO phase starts\n"));
*dophase_done = FALSE; /* not done yet */
/* start the first command in the DO phase */
state(conn, SSH_SFTP_QUOTE_INIT);
/* run the state-machine */
result = ssh_multi_statemach(conn, dophase_done);
*connected = conn->bits.tcpconnect[FIRSTSOCKET];
James Housley
committed
if(*dophase_done) {
James Housley
committed
DEBUGF(infof(conn->data, "DO phase is complete\n"));
}
return result;
}
/* called from multi.c while DOing */
static CURLcode sftp_doing(struct connectdata *conn,
bool *dophase_done)
James Housley
committed
{
CURLcode result;
result = ssh_multi_statemach(conn, dophase_done);
James Housley
committed
if(*dophase_done) {
James Housley
committed
DEBUGF(infof(conn->data, "DO phase is complete\n"));
}
return result;
}
/* BLOCKING, but the function is using the state machine so the only reason
this is still blocking is that the multi interface code has no support for
disconnecting operations that takes a while */
static CURLcode sftp_disconnect(struct connectdata *conn, bool dead_connection)
CURLcode result = CURLE_OK;
(void) dead_connection;
James Housley
committed
DEBUGF(infof(conn->data, "SSH DISCONNECT starts now\n"));
James Housley
committed
Curl_safefree(conn->data->req.protop);
Daniel Stenberg
committed
if(conn->proto.sshc.ssh_session) {
/* only if there's a session still around to use! */
state(conn, SSH_SFTP_SHUTDOWN);
result = ssh_block_statemach(conn, FALSE);
Daniel Stenberg
committed
}
James Housley
committed
DEBUGF(infof(conn->data, "SSH DISCONNECT is done\n"));
James Housley
committed
return result;
James Housley
committed
static CURLcode sftp_done(struct connectdata *conn, CURLcode status,
Patrick Monnerat
committed
bool premature)
James Housley
committed
struct ssh_conn *sshc = &conn->proto.sshc;
if(status == CURLE_OK) {
/* Post quote commands are executed after the SFTP_CLOSE state to avoid
errors that could happen due to open file handles during POSTQUOTE
operation */
if(!status && !premature && conn->data->set.postquote) {
sshc->nextstate = SSH_SFTP_POSTQUOTE_INIT;
state(conn, SSH_SFTP_CLOSE);
James Housley
committed
}
else
state(conn, SSH_SFTP_CLOSE);
James Housley
committed
}
Daniel Stenberg
committed
return ssh_done(conn, status);
/* return number of sent bytes */
static ssize_t sftp_send(struct connectdata *conn, int sockindex,
const void *mem, size_t len, CURLcode *err)
ssize_t nwrite; /* libssh2_sftp_write() used to return size_t in 0.14
but is changed to ssize_t in 0.15. These days we don't
support libssh2 0.15*/
(void)sockindex;
nwrite = libssh2_sftp_write(conn->proto.sshc.sftp_handle, mem, len);
Daniel Stenberg
committed
ssh_block2waitfor(conn, (nwrite == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE);
if(nwrite == LIBSSH2_ERROR_EAGAIN) {
*err = CURLE_AGAIN;
nwrite = 0;
}
else if(nwrite < LIBSSH2_ERROR_NONE) {
*err = libssh2_session_error_to_CURLE((int)nwrite);
nwrite = -1;
}
return nwrite;
}
* Return number of received (decrypted) bytes
static ssize_t sftp_recv(struct connectdata *conn, int sockindex,
char *mem, size_t len, CURLcode *err)
{
ssize_t nread;
(void)sockindex;
nread = libssh2_sftp_read(conn->proto.sshc.sftp_handle, mem, len);
Daniel Stenberg
committed
ssh_block2waitfor(conn, (nread == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE);
if(nread == LIBSSH2_ERROR_EAGAIN) {
*err = CURLE_AGAIN;
nread = -1;
}
return nread;
}
/* The get_pathname() function is being borrowed from OpenSSH sftp.c
version 4.6p1. */
/*
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
get_pathname(const char **cpp, char **path)
{
const char *cp = *cpp, *end;
char quot;
static const char WHITESPACE[] = " \t\r\n";
cp += strspn(cp, WHITESPACE);
if(!*cp) {
*cpp = cp;
*path = NULL;
return CURLE_QUOTE_ERROR;
}
*path = malloc(strlen(cp) + 1);
if(*path == NULL)
return CURLE_OUT_OF_MEMORY;
/* Check for quoted filenames */
if(*cp == '\"' || *cp == '\'') {
quot = *cp++;
/* Search for terminating quote, unescape some chars */
for(i = j = 0; i <= strlen(cp); i++) {
if(cp[i] == quot) { /* Found quote */
i++;
(*path)[j] = '\0';
break;
}
if(cp[i] == '\0') { /* End of string */
/*error("Unterminated quote");*/
goto fail;
}
if(cp[i] == '\\') { /* Escaped characters */
if(cp[i] != '\'' && cp[i] != '\"' &&
cp[i] != '\\') {
/*error("Bad escaped character '\\%c'",
cp[i]);*/
goto fail;
}
}
(*path)[j++] = cp[i];
}
if(j == 0) {
/*error("Empty quotes");*/
goto fail;
}
*cpp = cp + i + strspn(cp + i, WHITESPACE);
}
else {
/* Read to end of filename */
end = strpbrk(cp, WHITESPACE);
if(end == NULL)
end = strchr(cp, '\0');
*cpp = end + strspn(end, WHITESPACE);
memcpy(*path, cp, end - cp);
(*path)[end - cp] = '\0';
}
fail:
James Housley
committed
Curl_safefree(*path);
return CURLE_QUOTE_ERROR;
}
static const char *sftp_libssh2_strerror(int err)
{
switch (err) {
James Housley
committed
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
case LIBSSH2_FX_NO_SUCH_FILE:
return "No such file or directory";
case LIBSSH2_FX_PERMISSION_DENIED:
return "Permission denied";
case LIBSSH2_FX_FAILURE:
return "Operation failed";
case LIBSSH2_FX_BAD_MESSAGE:
return "Bad message from SFTP server";
case LIBSSH2_FX_NO_CONNECTION:
return "Not connected to SFTP server";
case LIBSSH2_FX_CONNECTION_LOST:
return "Connection to SFTP server lost";
case LIBSSH2_FX_OP_UNSUPPORTED:
return "Operation not supported by SFTP server";
case LIBSSH2_FX_INVALID_HANDLE:
return "Invalid handle";
case LIBSSH2_FX_NO_SUCH_PATH:
return "No such file or directory";
case LIBSSH2_FX_FILE_ALREADY_EXISTS:
return "File already exists";
case LIBSSH2_FX_WRITE_PROTECT:
return "File is write protected";
case LIBSSH2_FX_NO_MEDIA:
return "No media";
case LIBSSH2_FX_NO_SPACE_ON_FILESYSTEM:
return "Disk full";
case LIBSSH2_FX_QUOTA_EXCEEDED:
return "User quota exceeded";
case LIBSSH2_FX_UNKNOWN_PRINCIPLE:
return "Unknown principle";
case LIBSSH2_FX_LOCK_CONFlICT:
return "File lock conflict";
case LIBSSH2_FX_DIR_NOT_EMPTY:
return "Directory not empty";
case LIBSSH2_FX_NOT_A_DIRECTORY:
return "Not a directory";
case LIBSSH2_FX_INVALID_FILENAME:
return "Invalid filename";
case LIBSSH2_FX_LINK_LOOP:
return "Link points to itself";
}
return "Unknown error in libssh2";
}
#endif /* USE_LIBSSH2 */