SFTP added.

This commit is contained in:
Scott Duensing 2023-04-27 19:54:02 -05:00
parent 767e09969c
commit 232bbc0c53
5 changed files with 272 additions and 25 deletions

View file

@ -30,9 +30,11 @@
#include "common.h"
struct SFTPS;
struct SSHS;
typedef void (*SFTPCallback)(struct SFTPS*);
typedef void (*SSHCallback)(struct SSHS*);
@ -48,11 +50,35 @@ typedef struct SSHS {
} SSHT;
SSHT *sshConnect(char *hostname, uint16_t port, char *user, char *password);
void sshDisconnect(SSHT **sshData);
int sshExecute(SSHT *sshData, char *command, char **output);
void sshShutdown(void);
void sshStartup(void);
typedef struct SFTPS {
SSHT *sshData;
FILE *local;
LIBSSH2_SFTP *session;
LIBSSH2_SFTP_HANDLE *handle;
char buffer[102400];
char *ptr;
uint64_t fileSize;
uint64_t fileSent;
size_t nread;
char *source;
char *target;
char *title;
gboolean uploading;
gboolean readMore;
gboolean finished;
gboolean success;
GtkWidget *status;
SFTPCallback callback;
} SFTPT;
SSHT *sshConnect(char *hostname, uint16_t port, char *user, char *password);
void sshDisconnect(SSHT **sshData);
//int sshExecute(SSHT *sshData, char *command, char **output);
gboolean sshSFTPFileExists(SSHT *sshData, char *target);
SFTPT *sshSFTPSend(char *title, SSHT *sshData, char *source, char *target, SFTPCallback callback);
void sshShutdown(void);
void sshStartup(void);
#endif // SSH_H

View file

@ -47,9 +47,11 @@ char *utilFileBasename(char *path);
gboolean utilFileCopy(char *from, char *to);
gboolean utilFileExists(char *filename);
gboolean utilFileOpen(WindowDataT *self, char *extension, char *what);
char *utilFilePath(char *filename);
char *utilFileRemoveExtension(char *filename);
gboolean utilFileSaveAs(WindowDataT *self, char *extension, char *what);
gboolean utilFileSaveOtherAs(WindowDataT *self, char *extension, char *what, char **filename);
size_t utilFileSize(char *filename);
GtkWidget *utilFindChildWidget(GtkWidget *parent, const gchar *name);
char *utilGetToken(char *input, char *delimit, char *openblock, char *closeblock);
WindowDataT *utilGetWindowData(GtkWidget *window);

View file

@ -937,6 +937,7 @@ EVENT void menuProjectBuildCookRecipes(GtkWidget *object, gpointer userData) {
EVENT void menuProjectBuildBuild(GtkWidget *object, gpointer userData) {
//***TODO***
}

216
src/ssh.c
View file

@ -28,6 +28,7 @@
#include "ssh.h"
#include "utils.h"
#include "array.h"
#include "messages.h"
#ifdef _WIN32
@ -38,14 +39,16 @@ closesocket(data->sock);
#endif
static SSHT **_activeSSHs = NULL;
static char *_output = NULL;
static int _outputLen = 0;
static char *_buffer = NULL;
static int _bufferLen = 0;
static SFTPT **_activeSFTPs = NULL;
static SSHT **_activeSSHs = NULL;
static char *_output = NULL;
static int _outputLen = 0;
static char *_buffer = NULL;
static int _bufferLen = 0;
gboolean sshUpdate(gpointer userData); // Not static
gboolean sshSFTPUpdate(gpointer userData); // Not static
static int sshWaitSocket(int socket_fd, LIBSSH2_SESSION *session);
@ -58,13 +61,13 @@ SSHT *sshConnect(char *hostname, uint16_t port, char *user, char *password) {
hostent = gethostbyname(hostname);
if (hostent == NULL) {
debug("gethostbyname() failed.\n");
message(MSG_SEVERE, "gethostbyname() failed.\n");
return NULL;
}
hostaddr = inet_addr(inet_ntoa(*(struct in_addr*)*(hostent->h_addr_list)));
if (hostaddr == (in_addr_t)-1) {
debug("inet_addr() failed.\n");
message(MSG_SEVERE, "inet_addr() failed.\n");
return NULL;
}
@ -77,7 +80,7 @@ SSHT *sshConnect(char *hostname, uint16_t port, char *user, char *password) {
sin.sin_port = htons(port);
sin.sin_addr.s_addr = hostaddr;
if (connect(data->sock, (struct sockaddr*)(&sin), sizeof(struct sockaddr_in)) != 0) {
debug("connect() failed: %d\n", errno);
message(MSG_ERROR, "connect() failed: %d\n", errno);
DEL(data);
return NULL;
}
@ -94,7 +97,7 @@ SSHT *sshConnect(char *hostname, uint16_t port, char *user, char *password) {
while ((rc = libssh2_session_handshake(data->session, data->sock)) == LIBSSH2_ERROR_EAGAIN)
;
if (rc) {
debug("Failure establishing SSH session: %d\n", rc);
message(MSG_ERROR, "Failure establishing SSH session: %d\n", rc);
libssh2_session_free(data->session);
socketclose(data->sock);
DEL(data);
@ -104,7 +107,7 @@ SSHT *sshConnect(char *hostname, uint16_t port, char *user, char *password) {
while ((rc = libssh2_userauth_password(data->session, user, password)) == LIBSSH2_ERROR_EAGAIN)
;
if (rc) {
debug("Failure authenticating SSH session: %d\n", rc);
message(MSG_ERROR, "Failure authenticating SSH session: %d\n", rc);
while (libssh2_session_disconnect(data->session, "Error") == LIBSSH2_ERROR_EAGAIN)
;
libssh2_session_free(data->session);
@ -129,6 +132,7 @@ void sshDisconnect(SSHT **sshData) {
}
/*
int sshExecute(SSHT *sshData, char *command, char **output) {
int rc;
int exitcode = 127;
@ -201,18 +205,207 @@ SSHT *sshExecuteVerbose(SSHT *sshData, char *title, char *command, SSHCallback c
return NULL;
}
//***TODO*** SSH Progress Dialog Here
// ***TODO*** SSH Progress Dialog Here
//sshData->status = new SSHStatus(sshData);
arrpush(_activeSSHs, sshData);
return sshData;
}
*/
gboolean sshSFTPFileExists(SSHT *sshData, char *target) {
LIBSSH2_SFTP *session;
LIBSSH2_SFTP_HANDLE *handle;
LIBSSH2_SFTP_ATTRIBUTES attrs;
char *path;
char *file;
char buffer[512];
int rc;
gboolean result = FALSE;
do {
session = libssh2_sftp_init(sshData->session);
if (!session) {
if (libssh2_session_last_errno(sshData->session) != LIBSSH2_ERROR_EAGAIN) {
return FALSE;
}
}
} while (!session);
path = utilFilePath(target);
file = utilFileBasename(target);
do {
handle = libssh2_sftp_opendir(session, path);
if ((!handle) && (libssh2_session_last_errno(sshData->session) != LIBSSH2_ERROR_EAGAIN)) {
libssh2_sftp_shutdown(session);
free(file);
free(path);
return FALSE;
}
} while (!handle);
do {
while ((rc = libssh2_sftp_readdir(handle, buffer, sizeof(buffer), &attrs)) == LIBSSH2_ERROR_EAGAIN) {
;
}
// rc is the size of the content in buffer
if (rc > 0) {
if (strcmp(buffer, file) == 0) {
result = TRUE;
break;
}
} else {
if (rc == LIBSSH2_ERROR_EAGAIN) {
// Blocking - do nothing
} else {
// Finished.
break;
}
}
} while(1);
free(file);
free(path);
libssh2_sftp_closedir(handle);
libssh2_sftp_shutdown(session);
return result;
}
SFTPT *sshSFTPSend(char *title, SSHT *sshData, char *source, char *target, SFTPCallback callback) {
SFTPT *sftp = NULL;
int i;
// Do not allow two of the same transfers to be started.
for (i=0; i<arrlen(_activeSFTPs); i++) {
if ((strcmp(_activeSFTPs[i]->source, source) == 0) && (strcmp(_activeSFTPs[i]->target, target) == 0)) {
// Return existing transfer handle.
return _activeSFTPs[i];
}
}
sftp = NEW(SFTPT);
if (sftp) {
sftp->fileSize = utilFileSize(source);
sftp->local = fopen(source, "rb");
if (sftp->local) {
sftp->fileSent = 0;
sftp->nread = 0;
sftp->ptr = NULL;
sftp->title = title;
sftp->source = source;
sftp->target = target;
sftp->sshData = sshData;
sftp->uploading = TRUE;
sftp->readMore = TRUE;
sftp->finished = FALSE;
sftp->success = FALSE;
sftp->callback = callback;
do {
sftp->session = libssh2_sftp_init(sshData->session);
if (!sftp->session) {
if (libssh2_session_last_errno(sshData->session) != LIBSSH2_ERROR_EAGAIN) {
break;
}
}
} while (!sftp->session);
do {
sftp->handle = libssh2_sftp_open(sftp->session, sftp->target, LIBSSH2_FXF_WRITE | LIBSSH2_FXF_CREAT | LIBSSH2_FXF_TRUNC, LIBSSH2_SFTP_S_IRUSR | LIBSSH2_SFTP_S_IWUSR | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IROTH);
if (!sftp->handle) {
if (libssh2_session_last_errno(sshData->session) != LIBSSH2_ERROR_EAGAIN) {
break;
}
}
} while (!sftp->handle);
if (sftp->handle) {
//***TODO*** SFTP Status Dialog
//sftp->status = new SFTPStatus(sftp);
arrput(_activeSFTPs, sftp);
return sftp;
} else {
message(MSG_SEVERE, "Failed to get SFTP handle! %d, %lu\n", libssh2_session_last_errno(sshData->session), libssh2_sftp_last_error(sftp->session));
libssh2_sftp_shutdown(sftp->session);
DEL(sftp);
}
} else {
DEL(sftp);
}
}
return NULL;
}
gboolean sshSFTPUpdate(gpointer userData) {
int i;
int rc;
int count = 0;
SFTPT *result = NULL;
(void)userData;
for (i=0; i<arrlen(_activeSFTPs); i++) {
count++;
// More data to read?
if (_activeSFTPs[i]->readMore) {
_activeSFTPs[i]->nread = fread(_activeSFTPs[i]->buffer, 1, sizeof(_activeSFTPs[i]->buffer), _activeSFTPs[i]->local);
if (_activeSFTPs[i]->nread <= 0) {
result = _activeSFTPs[i];
arrdel(_activeSFTPs, i);
break;
}
_activeSFTPs[i]->ptr = _activeSFTPs[i]->buffer;
_activeSFTPs[i]->readMore = FALSE;
}
// Is there data to send?
if (_activeSFTPs[i]->nread > 0) {
// Send data.
while ((rc = (int)libssh2_sftp_write(_activeSFTPs[i]->handle, _activeSFTPs[i]->ptr, _activeSFTPs[i]->nread)) == LIBSSH2_ERROR_EAGAIN) {
sshWaitSocket(_activeSFTPs[i]->sshData->sock, _activeSFTPs[i]->sshData->session);
}
if (rc >= 0) {
_activeSFTPs[i]->ptr += rc;
_activeSFTPs[i]->nread -= rc;
_activeSFTPs[i]->fileSent += rc;
} else {
// We need more data!
_activeSFTPs[i]->readMore = TRUE;
}
} else {
// We need more data!
_activeSFTPs[i]->readMore = TRUE;
}
}
if (result) {
result->finished = TRUE;
result->success = TRUE;
libssh2_sftp_close(result->handle);
libssh2_sftp_shutdown(result->session);
//***TODO*** Display in status dialog
//result->status->Finished();
//result->status->Close();
if (result->callback) {
result->callback(result);
}
DEL(result);
}
return count;
}
void sshShutdown(void) {
//***TODO*** Any active sessions?
g_idle_remove_by_data(sshUpdate);
g_idle_remove_by_data(sshSFTPUpdate);
DEL(_output);
DEL(_buffer);
@ -240,6 +433,7 @@ void sshStartup(void) {
utilEnsureBufferSize((unsigned char **)&_buffer, &_bufferLen, 0x4000);
g_idle_add(sshUpdate, sshUpdate);
g_idle_add(sshSFTPUpdate, sshSFTPUpdate);
}

View file

@ -177,6 +177,8 @@ char *utilFileBasename(char *path) {
size_t length;
char *newString = NULL;
// Returns filename without path.
cwk_path_get_basename(path, &basename, &length);
if (basename != NULL) newString = strdup(basename);
@ -272,6 +274,21 @@ gboolean utilFileOpen(WindowDataT *self, char *extension, char *what) {
}
char *utilFilePath(char *filename) {
int i;
char *temp = NULL;
if (filename) {
// Derive the path from the filename.
temp = strdup(filename);
cwk_path_get_dirname(temp, &i);
if (i > 0) temp[i] = 0;
}
return temp;
}
char *utilFileRemoveExtension(char *filename) {
int x = (int)strlen(filename) - 1;
char c;
@ -347,6 +364,21 @@ gboolean utilFileSaveOtherAs(WindowDataT *self, char *extension, char *what, cha
}
size_t utilFileSize(char *filename) {
size_t bytes = 0;
FILE *f = fopen(filename, "rb");
if (f) {
fseek(f, 0, SEEK_END);
bytes = ftell(f);
fclose(f);
}
return bytes;
}
GtkWidget *utilFindChildWidget(GtkWidget *parent, const gchar *name) {
GList *children = NULL;
GtkWidget *widget = NULL;
@ -599,16 +631,8 @@ void utilSetDirty(WindowDataT *self, gboolean dirty) {
void utilUpdatePath(WindowDataT *self) {
size_t i;
DEL(self->path);
if (self->filename) {
// Derive the path from the filename.
self->path = strdup(self->filename);
cwk_path_get_dirname(self->path, &i);
if (i > 0) self->path[i] = 0;
}
self->path = utilFilePath(self->filename);
}