Skip to content
Snippets Groups Projects
Commit 530724a4 authored by Deucе's avatar Deucе :ok_hand_tone4:
Browse files

Start working on the SFTP server code.

The server is a lot thinner, with callbacks for each operation.
parent e53f1731
No related branches found
No related tags found
No related merge requests found
......@@ -2,5 +2,6 @@ MT_OBJS = \
$(MTOBJODIR)$(DIRSEP)sftp_pkt$(OFILE) \
$(MTOBJODIR)$(DIRSEP)sftp_str$(OFILE) \
$(MTOBJODIR)$(DIRSEP)sftp_client$(OFILE) \
$(MTOBJODIR)$(DIRSEP)sftp_server$(OFILE) \
$(MTOBJODIR)$(DIRSEP)sftp_attr$(OFILE) \
......@@ -59,7 +59,7 @@
#define SSH_FILEXFER_ATTR_EXTENDED UINT32_C(0x80000000)
#define SFTP_MIN_PACKET_ALLOC 4096
#define SFTP_VERSION 3
#define SFTP_VERSION UINT32_C(3)
typedef struct sftp_tx_pkt {
uint32_t sz;
......@@ -90,16 +90,24 @@ struct sftp_extended_file_attribute {
struct sftp_file_attributes;
typedef struct sftp_file_attributes *sftp_file_attr_t;
enum sftp_handle_type {
SFTP_HANDLE_TYPE_DIR,
SFTP_HANDLE_TYPE_FILE,
};
typedef sftp_str_t sftp_filehandle_t;
typedef sftp_str_t sftp_dirhandle_t;
typedef struct sftp_client_state {
bool (*send_cb)(uint8_t *buf, size_t len, void *cb_data);
xpevent_t recv_event;
sftp_rx_pkt_t rxp;
sftp_tx_pkt_t txp;
sftp_str_t home;
void *cb_data;
sftp_str_t err_msg;
sftp_str_t err_lang;
pthread_mutex_t mtx;
uint32_t version;
uint32_t running;
uint32_t id;
uint32_t err_id;
......@@ -107,13 +115,37 @@ typedef struct sftp_client_state {
bool terminating;
} *sftpc_state_t;
enum sftp_handle_type {
SFTP_HANDLE_TYPE_DIR,
SFTP_HANDLE_TYPE_FILE,
};
typedef sftp_str_t sftp_filehandle_t;
typedef sftp_str_t sftp_dirhandle_t;
typedef struct sftp_server_state {
bool (*send_cb)(uint8_t *buf, size_t len, void *cb_data);
sftp_rx_pkt_t rxp;
sftp_tx_pkt_t txp;
void *cb_data;
void (*lprintf)(const char *fmt, ...);
bool (*open)(sftp_str_t filename, uint32_t flags, sftp_file_attr_t attributes, void *cb_data);
bool (*close)(sftp_str_t handle, void *cb_data);
bool (*read)(sftp_filehandle_t handle, uint64_t offset, uint32_t len, void *cb_data);
bool (*write)(sftp_filehandle_t handle, uint64_t offset, sftp_str_t data, void *cb_data);
bool (*remove)(sftp_str_t filename, void *cb_data);
bool (*rename)(sftp_str_t oldpath, sftp_str_t newpath, void *cb_data);
bool (*mkdir)(sftp_str_t path, sftp_file_attr_t attributes, void *cb_data);
bool (*rmdir)(sftp_str_t path, void *cb_data);
bool (*opendir)(sftp_str_t path, void *cb_data);
bool (*readdir)(sftp_str_t handle, void *cb_data);
bool (*stat)(sftp_str_t path, void *cb_data);
bool (*lstat)(sftp_str_t path, void *cb_data);
bool (*fstat)(sftp_filehandle_t handle, void *cb_data);
bool (*setstat)(sftp_str_t path, sftp_file_attr_t attributes, void *cb_data);
bool (*fsetstat)(sftp_filehandle_t handle, sftp_file_attr_t attributes, void *cb_data);
bool (*readlink)(sftp_str_t path, void *cb_data);
bool (*symlink)(sftp_str_t linkpath, sftp_str_t targetpath, void *cb_data);
bool (*realpath)(sftp_str_t path, void *cb_data);
bool (*extended)(sftp_str_t request, sftp_rx_pkt_t pkt, void *cb_data);
pthread_mutex_t mtx;
uint32_t running;
uint32_t id;
uint32_t version;
bool terminating;
} *sftps_state_t;
/* sftp_pkt.c */
const char * const sftp_get_type_name(uint8_t type);
......@@ -132,6 +164,7 @@ bool sftp_appendbyte(sftp_tx_pkt_t *pktp, uint8_t u8);
bool sftp_append32(sftp_tx_pkt_t *pktp, uint32_t u32);
bool sftp_append64(sftp_tx_pkt_t *pktp, uint64_t u);
bool sftp_appendstring(sftp_tx_pkt_t *pktp, sftp_str_t s);
bool sftp_appendcstring(sftp_tx_pkt_t *pktp, const char *str);
void sftp_free_tx_pkt(sftp_tx_pkt_t pkt);
void sftp_free_rx_pkt(sftp_rx_pkt_t pkt);
bool sftp_prep_tx_packet(sftp_tx_pkt_t pkt, uint8_t **buf, size_t *sz);
......@@ -171,5 +204,12 @@ sftp_str_t sftp_fattr_get_ext_type(sftp_file_attr_t fattr, uint32_t index);
sftp_str_t sftp_fattr_get_ext_data(sftp_file_attr_t fattr, uint32_t index);
uint32_t sftp_fattr_get_ext_count(sftp_file_attr_t fattr);
bool sftp_appendfattr(sftp_tx_pkt_t *pktp, sftp_file_attr_t fattr);
sftp_file_attr_t sftp_getfattr(sftp_rx_pkt_t pkt);
/* sftp_server.c */
bool sftps_recv(sftps_state_t state, uint8_t *buf, uint32_t sz);
sftps_state_t sftps_begin(bool (*send_cb)(uint8_t *buf, size_t len, void *cb_data), void *cb_data);
bool sftps_send_packet(sftps_state_t state);
bool sftps_send_error(sftps_state_t state, uint32_t code, const char *msg);
#endif
......@@ -112,6 +112,7 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="sftp_client.c" />
<ClCompile Include="sftp_server.c" />
<ClCompile Include="sftp_attr.c" />
<ClCompile Include="sftp_pkt.c" />
<ClCompile Include="sftp_str.c" />
......
......@@ -281,3 +281,52 @@ fail:
(*pktp)->used = oldused;
return false;
}
sftp_file_attr_t
sftp_getfattr(sftp_rx_pkt_t pkt)
{
sftp_file_attr_t ret = sftp_fattr_alloc();
if (ret == NULL)
return ret;
ret->flags = sftp_get32(pkt);
if (ret->flags & SSH_FILEXFER_ATTR_SIZE) {
ret->size = sftp_get64(pkt);
}
if (ret->flags & SSH_FILEXFER_ATTR_UIDGID) {
ret->uid = sftp_get32(pkt);
ret->gid = sftp_get32(pkt);
}
if (ret->flags & SSH_FILEXFER_ATTR_PERMISSIONS) {
ret->perm = sftp_get32(pkt);
}
if (ret->flags & SSH_FILEXFER_ATTR_ACMODTIME) {
ret->atime = sftp_get32(pkt);
ret->mtime = sftp_get32(pkt);
}
if (ret->flags & SSH_FILEXFER_ATTR_EXTENDED) {
uint32_t extcnt = sftp_get32(pkt);
uint32_t ext;
for (ext = 0; ext < extcnt; ext++) {
sftp_str_t type = sftp_getstring(pkt);
if (type == NULL)
break;
sftp_str_t data = sftp_getstring(pkt);
if (data == NULL) {
free_sftp_str(type);
break;
}
if (!sftp_fattr_add_ext(&ret, type, data)) {
free_sftp_str(type);
free_sftp_str(data);
break;
}
free_sftp_str(type);
free_sftp_str(data);
}
if (ext != extcnt) {
sftp_fattr_free(ret);
return NULL;
}
}
return ret;
}
......@@ -5,35 +5,9 @@
#include "sftp.h"
static uint32_t
get32(sftpc_state_t state)
{
return sftp_get32(state->rxp);
}
static uint64_t
get64(sftpc_state_t state)
{
return sftp_get64(state->rxp);
}
static sftp_str_t
getstring(sftpc_state_t state)
{
return sftp_getstring(state->rxp);
}
static bool
appendbyte(sftpc_state_t state, uint8_t u)
{
return sftp_appendbyte(&state->txp, u);
}
static bool
append32(sftpc_state_t state, uint32_t u)
{
return sftp_append32(&state->txp, u);
}
#define SFTP_STATIC_TYPE sftpc_state_t
#include "sftp_static.h"
#undef SFTP_STATIC_TYPE
static bool
append64(sftpc_state_t state, uint64_t u)
......@@ -42,9 +16,10 @@ append64(sftpc_state_t state, uint64_t u)
}
static bool
appendfattr(sftpc_state_t state, sftp_file_attr_t fattr)
appendstring(sftpc_state_t state, sftp_str_t s)
{
return sftp_appendfattr(&state->txp, fattr);
bool ret = sftp_appendstring(&state->txp, s);
return ret;
}
static bool
......@@ -57,85 +32,25 @@ appendandfreestring(sftpc_state_t state, sftp_str_t *s)
}
static bool
appendstring(sftpc_state_t state, sftp_str_t s)
{
bool ret = sftp_appendstring(&state->txp, s);
return ret;
}
void
sftpc_finish(sftpc_state_t state)
{
assert(state);
if (state == NULL)
return;
pthread_mutex_lock(&state->mtx);
state->terminating = true;
pthread_mutex_unlock(&state->mtx);
// TODO: Close all open handles
while (!CloseEvent(state->recv_event)) {
assert(errno == EBUSY);
if (errno != EBUSY)
break;
SetEvent(state->recv_event);
SLEEP(1);
}
pthread_mutex_lock(&state->mtx);
while (state->running) {
pthread_mutex_unlock(&state->mtx);
SLEEP(1);
pthread_mutex_lock(&state->mtx);
}
sftp_free_rx_pkt(state->rxp);
sftp_free_tx_pkt(state->txp);
pthread_mutex_unlock(&state->mtx);
pthread_mutex_destroy(&state->mtx);
free(state);
}
sftpc_state_t
sftpc_begin(bool (*send_cb)(uint8_t *buf, size_t len, void *cb_data), void *cb_data)
appendfhandle(sftpc_state_t state, sftp_filehandle_t handle)
{
sftpc_state_t ret = (sftpc_state_t)malloc(sizeof(struct sftp_client_state));
if (ret == NULL)
return NULL;
ret->recv_event = CreateEvent(NULL, TRUE, FALSE, NULL);
if (ret->recv_event == NULL) {
free(ret);
return NULL;
}
ret->rxp = NULL;
ret->txp = NULL;
ret->send_cb = send_cb;
ret->cb_data = cb_data;
ret->id = 0;
ret->err_lang = NULL;
ret->err_msg = NULL;
ret->running = 0;
pthread_mutex_init(&ret->mtx, NULL);
ret->terminating = false;
return ret;
return appendstring(state, (sftp_str_t)handle);
}
static void
response_handled(sftpc_state_t state)
static bool
appenddhandle(sftpc_state_t state, sftp_dirhandle_t handle)
{
sftp_remove_packet(state->rxp);
if (!sftp_have_full_pkt(state->rxp))
ResetEvent(state->recv_event);
return appendstring(state, (sftp_str_t)handle);
}
static bool
check_state(sftpc_state_t state)
appendfattr(sftpc_state_t state, sftp_file_attr_t fattr)
{
assert(state);
if (!state)
return false;
return true;
return sftp_appendfattr(&state->txp, fattr);
}
static bool
appendheader(sftpc_state_t state, uint8_t type)
cappendheader(sftpc_state_t state, uint8_t type)
{
state->err_code = 0;
state->err_id = 0;
......@@ -143,27 +58,7 @@ appendheader(sftpc_state_t state, uint8_t type)
state->err_lang = NULL;
free_sftp_str(state->err_msg);
state->err_msg = NULL;
if (!sftp_tx_pkt_reset(&state->txp))
return false;
if (!sftp_appendbyte(&state->txp, type))
return false;
if (type != SSH_FXP_INIT) {
if (!sftp_append32(&state->txp, ++state->id))
return false;
}
return true;
}
static bool
appendfhandle(sftpc_state_t state, sftp_filehandle_t handle)
{
return appendstring(state, (sftp_str_t)handle);
}
static bool
appenddhandle(sftpc_state_t state, sftp_dirhandle_t handle)
{
return appendstring(state, (sftp_str_t)handle);
return appendheader(state, type);
}
static bool
......@@ -195,17 +90,27 @@ get_result(sftpc_state_t state)
return true;
}
static void
response_handled(sftpc_state_t state)
{
sftp_remove_packet(state->rxp);
if (!sftp_have_full_pkt(state->rxp))
ResetEvent(state->recv_event);
}
static void
handle_error(sftpc_state_t state)
{
if (state->rxp->type == SSH_FXP_STATUS) {
state->err_code = get32(state);
if (state->err_msg != NULL)
free_sftp_str(state->err_msg);
state->err_msg = getstring(state);
if (state->err_lang != NULL)
free_sftp_str(state->err_lang);
state->err_lang = getstring(state);
if (state->version > 2) {
if (state->err_msg != NULL)
free_sftp_str(state->err_msg);
state->err_msg = getstring(state);
if (state->err_lang != NULL)
free_sftp_str(state->err_lang);
state->err_lang = getstring(state);
}
}
response_handled(state);
}
......@@ -228,28 +133,58 @@ parse_handle(sftpc_state_t state, sftp_str_t *handle)
return true;
}
static bool
enter_function(sftpc_state_t state)
void
sftpc_finish(sftpc_state_t state)
{
if (!check_state(state))
return false;
if (pthread_mutex_lock(&state->mtx))
return false;
if (state->terminating) {
assert(state);
if (state == NULL)
return;
pthread_mutex_lock(&state->mtx);
state->terminating = true;
pthread_mutex_unlock(&state->mtx);
// TODO: Close all open handles
while (!CloseEvent(state->recv_event)) {
assert(errno == EBUSY);
if (errno != EBUSY)
break;
SetEvent(state->recv_event);
SLEEP(1);
}
pthread_mutex_lock(&state->mtx);
while (state->running) {
pthread_mutex_unlock(&state->mtx);
return false;
SLEEP(1);
pthread_mutex_lock(&state->mtx);
}
state->running++;
return true;
sftp_free_rx_pkt(state->rxp);
sftp_free_tx_pkt(state->txp);
pthread_mutex_unlock(&state->mtx);
pthread_mutex_destroy(&state->mtx);
free(state);
}
static bool
exit_function(sftpc_state_t state, bool retval)
sftpc_state_t
sftpc_begin(bool (*send_cb)(uint8_t *buf, size_t len, void *cb_data), void *cb_data)
{
assert(state->running > 0);
state->running--;
pthread_mutex_unlock(&state->mtx);
return retval;
sftpc_state_t ret = (sftpc_state_t)malloc(sizeof(struct sftp_client_state));
if (ret == NULL)
return NULL;
ret->recv_event = CreateEvent(NULL, TRUE, FALSE, NULL);
if (ret->recv_event == NULL) {
free(ret);
return NULL;
}
ret->rxp = NULL;
ret->txp = NULL;
ret->send_cb = send_cb;
ret->cb_data = cb_data;
ret->id = 0;
ret->err_lang = NULL;
ret->err_msg = NULL;
ret->running = 0;
pthread_mutex_init(&ret->mtx, NULL);
ret->terminating = false;
return ret;
}
bool
......@@ -257,7 +192,7 @@ sftpc_init(sftpc_state_t state)
{
if (!enter_function(state))
return false;
if (!appendheader(state, SSH_FXP_INIT))
if (!cappendheader(state, SSH_FXP_INIT))
return exit_function(state, false);
if (!append32(state, SFTP_VERSION))
return exit_function(state, false);
......@@ -265,7 +200,8 @@ sftpc_init(sftpc_state_t state)
return exit_function(state, false);
if (state->rxp->type != SSH_FXP_VERSION)
return exit_function(state, false);
if (get32(state) != SFTP_VERSION) {
state->version = get32(state);
if (state->version > SFTP_VERSION) {
response_handled(state);
return exit_function(state, false);
}
......@@ -296,7 +232,7 @@ sftpc_realpath(sftpc_state_t state, char *path, sftp_str_t *ret)
return exit_function(state, false);
if (*ret != NULL)
return exit_function(state, false);
if (!appendheader(state, SSH_FXP_REALPATH))
if (!cappendheader(state, SSH_FXP_REALPATH))
return exit_function(state, false);
sftp_str_t pstr = sftp_strdup(path);
if (!appendandfreestring(state, &pstr))
......@@ -330,7 +266,7 @@ sftpc_open(sftpc_state_t state, char *path, uint32_t flags, sftp_file_attr_t att
assert(!*handle);
if (*handle != NULL)
return exit_function(state, false);
if (!appendheader(state, SSH_FXP_OPEN))
if (!cappendheader(state, SSH_FXP_OPEN))
return exit_function(state, false);
sftp_str_t pstr = sftp_strdup(path);
if (!appendandfreestring(state, &pstr))
......@@ -369,7 +305,7 @@ sftpc_close(sftpc_state_t state, sftp_filehandle_t *handle)
{
if (!enter_function(state))
return false;
if (!appendheader(state, SSH_FXP_CLOSE))
if (!cappendheader(state, SSH_FXP_CLOSE))
return exit_function(state, false);
if (!appendfhandle(state, *handle))
return exit_function(state, false);
......@@ -392,7 +328,7 @@ sftpc_read(sftpc_state_t state, sftp_filehandle_t handle, uint64_t offset, uint3
assert(*ret == NULL);
if (*ret != NULL)
return exit_function(state, false);
if (!appendheader(state, SSH_FXP_READ))
if (!cappendheader(state, SSH_FXP_READ))
return exit_function(state, false);
if (!appendfhandle(state, handle))
return exit_function(state, false);
......@@ -419,7 +355,7 @@ sftpc_write(sftpc_state_t state, sftp_filehandle_t handle, uint64_t offset, sftp
assert(data);
if (data == NULL)
return exit_function(state, false);
if (!appendheader(state, SSH_FXP_WRITE))
if (!cappendheader(state, SSH_FXP_WRITE))
return exit_function(state, false);
if (!appendfhandle(state, handle))
return exit_function(state, false);
......
......@@ -334,6 +334,40 @@ sftp_appendstring(sftp_tx_pkt_t *pktp, sftp_str_t s)
return true;
}
bool
sftp_appendcstring(sftp_tx_pkt_t *pktp, const char *str)
{
uint32_t oldused;
uint32_t len;
size_t sz;
assert(pktp);
if (*pktp == NULL)
oldused = 0;
else
oldused = (*pktp)->used;
assert(str);
if (str == NULL)
oldused = 0;
else
oldused = (*pktp)->used;
sz = strlen(str);
if (sz > UINT32_MAX)
return false;
len = sz;
if (!sftp_append32(pktp, len))
return false;
if (!grow_tx(pktp, len)) {
if (*pktp != NULL)
(*pktp)->used = oldused;
return false;
}
sftp_tx_pkt_t pkt = *pktp;
memcpy(&(&pkt->type)[pkt->used], str, len);
pkt->used += len;
return true;
}
bool
sftp_prep_tx_packet(sftp_tx_pkt_t pkt, uint8_t **buf, size_t *sz)
{
......
#include <assert.h>
#include <genwrap.h>
#include <stdlib.h>
#include <threadwrap.h>
#include "sftp.h"
#define SFTP_STATIC_TYPE sftps_state_t
#include "sftp_static.h"
#undef SFTP_STATIC_TYPE
static uint64_t
get64(sftps_state_t state)
{
return sftp_get64(state->rxp);
}
static bool
appendcstring(sftps_state_t state, const char *s)
{
bool ret = sftp_appendcstring(&state->txp, s);
return ret;
}
static bool
init(sftps_state_t state)
{
state->version = get32(state);
if (state->version > SFTP_VERSION)
state->version = SFTP_VERSION;
if (!appendheader(state, state->version))
return false;
if (!append32(state, SFTP_VERSION))
return false;
return sftps_send_packet(state);
}
sftps_state_t
sftps_begin(bool (*send_cb)(uint8_t *buf, size_t len, void *cb_data), void *cb_data)
{
sftps_state_t ret = (sftps_state_t)calloc(1, sizeof(struct sftp_server_state));
if (ret == NULL)
return NULL;
ret->rxp = NULL;
ret->txp = NULL;
ret->send_cb = send_cb;
ret->cb_data = cb_data;
ret->id = 0;
ret->running = 0;
pthread_mutex_init(&ret->mtx, NULL);
ret->terminating = false;
return ret;
}
bool
sftps_send_packet(sftps_state_t state)
{
uint8_t *txbuf;
size_t txsz;
if (!sftp_prep_tx_packet(state->txp, &txbuf, &txsz))
return false;
if (!state->send_cb(txbuf, txsz, state->cb_data))
return false;
return true;
}
bool
sftps_send_error(sftps_state_t state, uint32_t code, const char *msg)
{
if (!appendheader(state, SSH_FXP_STATUS))
return false;
if (!append32(state, state->id))
return false;
if (!append32(state, code))
return false;
if (state->version >= 3) {
if (!appendcstring(state, msg))
return false;
if (!appendcstring(state, "en-CA"))
return false;
}
return sftps_send_packet(state);
}
static bool
s_open(sftps_state_t state)
{
bool ret;
sftp_str_t fname;
uint32_t flags;
sftp_file_attr_t attrs;
state->id = get32(state);
fname = getstring(state);
if (fname == NULL)
return false;
flags = get32(state);
attrs = sftp_getfattr(state->rxp);
if (attrs == NULL) {
free_sftp_str(fname);
return false;
}
ret = state->open(fname, flags, attrs, state->cb_data);
sftp_fattr_free(attrs);
free_sftp_str(fname);
return ret;
}
static bool
s_read(sftps_state_t state)
{
bool ret;
sftp_filehandle_t handle;
uint64_t offset;
uint32_t len;
state->id = get32(state);
handle = getstring(state);
if (handle == NULL)
return false;
offset = get64(state);
len = get32(state);
ret = state->read(handle, offset, len, state->cb_data);
free_sftp_str(handle);
return ret;
}
static bool
s_write(sftps_state_t state)
{
bool ret;
sftp_filehandle_t handle;
uint64_t offset;
sftp_str_t data;
state->id = get32(state);
handle = getstring(state);
if (handle == NULL)
return false;
offset = get64(state);
data = getstring(state);
if (data == NULL) {
free_sftp_str(handle);
return false;
}
ret = state->write(handle, offset, data, state->cb_data);
free_sftp_str(handle);
free_sftp_str(data);
return ret;
}
static bool
s_id_str(sftps_state_t state, bool (*cb)(sftp_str_t, void *))
{
bool ret;
sftp_str_t str;
state->id = get32(state);
str = getstring(state);
if (str == NULL)
return false;
ret = cb(str, state->cb_data);
free_sftp_str(str);
return ret;
}
static bool
s_fstat(sftps_state_t state)
{
bool ret;
sftp_filehandle_t handle;
state->id = get32(state);
handle = getstring(state);
if (handle == NULL)
return false;
ret = state->fstat(handle, state->cb_data);
free_sftp_str(handle);
return ret;
}
static bool
s_id_str_attr(sftps_state_t state, bool (*cb)(sftp_str_t, sftp_file_attr_t, void *))
{
bool ret;
sftp_str_t str;
sftp_file_attr_t attrs;
state->id = get32(state);
str = getstring(state);
if (str == NULL)
return false;
attrs = sftp_getfattr(state->rxp);
if (attrs == NULL) {
free_sftp_str(str);
return false;
}
ret = cb(str, attrs, state->cb_data);
free_sftp_str(str);
sftp_fattr_free(attrs);
return ret;
}
bool
s_fsetstat(sftps_state_t state)
{
bool ret;
sftp_filehandle_t handle;
sftp_file_attr_t attrs;
state->id = get32(state);
handle = getstring(state);
if (handle == NULL)
return false;
attrs = sftp_getfattr(state->rxp);
if (attrs == NULL) {
free_sftp_str(handle);
return false;
}
ret = state->fsetstat(handle, attrs, state->cb_data);
free_sftp_str(handle);
sftp_fattr_free(attrs);
return ret;
}
static bool
s_id_str_str(sftps_state_t state, bool (*cb)(sftp_str_t, sftp_str_t, void *))
{
bool ret;
sftp_str_t str1;
sftp_str_t str2;
state->id = get32(state);
str1 = getstring(state);
if (str1 == NULL)
return false;
str2 = getstring(state);
if (str2 == NULL) {
free_sftp_str(str1);
return false;
}
ret = cb(str1, str2, state->cb_data);
free_sftp_str(str1);
free_sftp_str(str2);
return ret;
}
bool
sftps_recv(sftps_state_t state, uint8_t *buf, uint32_t sz)
{
if (!enter_function(state))
return false;
if (!sftp_rx_pkt_append(&state->rxp, buf, sz))
return exit_function(state, false);
while (sftp_have_full_pkt(state->rxp)) {
bool handled = false;
switch(state->rxp->type) {
case SSH_FXP_INIT:
if (!init(state))
return exit_function(state, false);
break;
case SSH_FXP_OPEN:
if (state->open) {
if (!s_open(state))
return exit_function(state, false);
handled = true;
}
break;
case SSH_FXP_CLOSE:
if (state->close) {
if (!s_id_str(state, state->close))
return exit_function(state, false);
handled = true;
}
break;
case SSH_FXP_READ:
if (state->read) {
if (!s_read(state))
return exit_function(state, false);
handled = true;
}
break;
case SSH_FXP_WRITE:
if (state->write) {
if (!s_write(state))
return exit_function(state, false);
handled = true;
}
break;
case SSH_FXP_LSTAT:
if (state->lstat) {
if (!s_id_str(state, state->lstat))
return exit_function(state, false);
handled = true;
}
break;
case SSH_FXP_FSTAT:
if (state->fstat) {
if (!s_fstat(state))
return exit_function(state, false);
handled = true;
}
break;
case SSH_FXP_SETSTAT:
if (state->setstat) {
if (!s_id_str_attr(state, state->setstat))
return exit_function(state, false);
handled = true;
}
break;
case SSH_FXP_FSETSTAT:
if (state->fsetstat) {
if (!s_fsetstat(state))
return exit_function(state, false);
handled = true;
}
break;
case SSH_FXP_OPENDIR:
if (state->opendir) {
if (!s_id_str(state, state->opendir))
return exit_function(state, false);
handled = true;
}
break;
case SSH_FXP_READDIR:
if (state->readdir) {
if (!s_id_str(state, state->readdir))
return exit_function(state, false);
handled = true;
}
break;
case SSH_FXP_REMOVE:
if (state->remove) {
if (!s_id_str(state, state->remove))
return exit_function(state, false);
handled = true;
}
break;
case SSH_FXP_MKDIR:
if (state->mkdir) {
if (!s_id_str_attr(state, state->mkdir))
return exit_function(state, false);
handled = true;
}
break;
case SSH_FXP_RMDIR:
if (state->rmdir) {
if (!s_id_str(state, state->rmdir))
return exit_function(state, false);
handled = true;
}
break;
case SSH_FXP_REALPATH:
if (state->realpath) {
if (!s_id_str(state, state->realpath))
return exit_function(state, false);
handled = true;
}
break;
case SSH_FXP_STAT:
if (state->stat) {
if (!s_id_str(state, state->stat))
return exit_function(state, false);
handled = true;
}
break;
case SSH_FXP_RENAME:
if (state->version >= 2 && state->rename) {
if (!s_id_str_str(state, state->rename))
return exit_function(state, false);
handled = true;
}
break;
case SSH_FXP_READLINK:
if (state->version >= 3 && state->readlink) {
if (!s_id_str(state, state->readlink))
return exit_function(state, false);
handled = true;
}
break;
case SSH_FXP_SYMLINK:
if (state->version >= 3 && state->symlink) {
if (!s_id_str_str(state, state->symlink))
return exit_function(state, false);
handled = true;
}
break;
case SSH_FXP_EXTENDED:
if (state->version >= 3 && state->extended) {
state->id = get32(state);
sftp_str_t request = getstring(state);
if (request == NULL)
return exit_function(state, false);
handled = state->extended(request, state->rxp, state->cb_data);
free_sftp_str(request);
}
default:
break;
}
if (!handled) {
if (state->lprintf)
state->lprintf("Unhandled request type: %s (%d)", sftp_get_type_name(state->rxp->type), state->rxp->type);
state->id = get32(state);
if (!sftps_send_error(state, SSH_FX_OP_UNSUPPORTED, "Operation not implemented"))
return exit_function(state, false);
}
sftp_remove_packet(state->rxp);
}
return exit_function(state, true);
}
// Static functions "shared" between client and server
static uint32_t
get32(SFTP_STATIC_TYPE state)
{
return sftp_get32(state->rxp);
}
static sftp_str_t
getstring(SFTP_STATIC_TYPE state)
{
return sftp_getstring(state->rxp);
}
static bool
append32(SFTP_STATIC_TYPE state, uint32_t u)
{
return sftp_append32(&state->txp, u);
}
static bool
check_state(SFTP_STATIC_TYPE state)
{
assert(state);
if (!state)
return false;
return true;
}
static bool
appendheader(SFTP_STATIC_TYPE state, uint8_t type)
{
if (!sftp_tx_pkt_reset(&state->txp))
return false;
if (!sftp_appendbyte(&state->txp, type))
return false;
if (type != SSH_FXP_INIT) {
if (!sftp_append32(&state->txp, ++state->id))
return false;
}
return true;
}
static bool
enter_function(SFTP_STATIC_TYPE state)
{
if (!check_state(state))
return false;
if (pthread_mutex_lock(&state->mtx))
return false;
if (state->terminating) {
pthread_mutex_unlock(&state->mtx);
return false;
}
state->running++;
return true;
}
static bool
exit_function(SFTP_STATIC_TYPE state, bool retval)
{
assert(state->running > 0);
state->running--;
pthread_mutex_unlock(&state->mtx);
return retval;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment