diff options
Diffstat (limited to 'src/mscp.c')
-rw-r--r-- | src/mscp.c | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/src/mscp.c b/src/mscp.c new file mode 100644 index 0000000..d1d8fa8 --- /dev/null +++ b/src/mscp.c @@ -0,0 +1,190 @@ +#include <stdbool.h> +#include <unistd.h> +#include <signal.h> +#include <sys/time.h> +#include <sys/ioctl.h> +#include <math.h> +#include <pthread.h> + +#include <list.h> +#include <util.h> +#include <ssh.h> +#include <path.h> +#include <pprint.h> +#include <atomic.h> +#include <platform.h> +#include <mscp.h> + +struct mscp { + const char *remote; /* remote host (and uername) */ + struct mscp_opts *opts; + struct ssh_opts ssh_opts; + + sftp_session first; /* first sftp session */ + + char dst_path[PATH_MAX]; + struct list_head src_list; + struct list_head path_list; + struct list_head chunk_list; + lock chunk_lock; + + struct mscp_thread *threads; +}; + +struct src { + struct list_head list; + char *path; +}; + +#define DEFAULT_MIN_CHUNK_SZ (64 << 20) /* 64MB */ +#define DEFAULT_NR_AHEAD 32 +#define DEFAULT_BUF_SZ 16384 + +struct mscp *mscp_init(const char *remote_host, struct mscp_opts *opts) +{ + struct mscp *m; + + m = malloc(sizeof(*m)); + if (!m) { + pr_err("failed to allocate memory: %s\n", strerrno()); + return NULL; + } + + memset(m, 0, sizeof(*m)); + INIT_LIST_HEAD(&m->src_list); + INIT_LIST_HEAD(&m->path_list); + INIT_LIST_HEAD(&m->chunk_list); + lock_init(&m->chunk_lock); + m->remote = strdup(remote_host); + if (!m->remote) { + pr_err("failed to allocate memory: %s\n", strerrno()); + free(m); + return NULL; + } + + m->opts = opts; + m->ssh_opts.login_name = opts->ssh_login_name; + m->ssh_opts.port = opts->ssh_port; + m->ssh_opts.identity = opts->ssh_identity; + m->ssh_opts.cipher = opts->ssh_cipher_spec; + m->ssh_opts.hmac = opts->ssh_hmac_spec; + m->ssh_opts.compress = opts->ssh_compress_level; + m->ssh_opts.debuglevel = opts->ssh_debug_level; + m->ssh_opts.no_hostkey_check = opts->ssh_no_hostkey_check; + m->ssh_opts.nodelay = opts->ssh_disable_tcp_nodely; + + m->first = ssh_init_sftp_session(m->remote, &m->ssh_opts); + if (!m->first) { + free(m); + return NULL; + } + + return m; +} + +int mscp_add_src_path(struct mscp *m, const char *src_path) +{ + struct src *s; + + s = malloc(sizeof(*s)); + if (!s) { + pr_err("failed to allocate memory: %s\n", strerrno()); + return -1; + } + + memset(s, 0, sizeof(*s)); + s->path = strdup(src_path); + if (!s->path) { + pr_err("failed to allocate memory: %s\n", strerrno()); + free(s); + return -1; + } + + list_add_tail(&s->list, &m->src_list); + return 0; +} + +static void mscp_free_src_list(struct mscp *m) +{ + struct src *s, *n; + + list_for_each_entry_safe(s, n, &m->src_list, list) { + free(s->path); + list_del(&s->list); + free(s); + } +} + +int mscp_set_dst_path(struct mscp *m, const char *dst_path) +{ + if (strlen(dst_path) + 1 >= PATH_MAX) { + pr_err("too long dst path: %s\n", dst_path); + return -1; + } + + strncpy(m->dst_path, dst_path, PATH_MAX); + return 0; +} + +int mscp_prepare(struct mscp *m) +{ + sftp_session src_sftp = NULL, dst_sftp = NULL; + bool src_path_is_dir, dst_path_is_dir; + struct list_head tmp; + struct src *s; + mstat ss, ds; + + switch (m->opts->direct) { + case MSCP_DIRECT_L2R: + src_sftp = NULL; + dst_sftp = m->first; + break; + case MSCP_DIRECT_R2L: + src_sftp = m->first; + dst_sftp = NULL; + break; + default: + pr_err("invalid mscp direction: %d\n", m->opts->direct); + return -1; + } + + if (mscp_stat(m->dst_path, &ds, dst_sftp) == 0) { + if (mstat_is_dir(ds)) + dst_path_is_dir = true; + mscp_stat_free(ds); + } else + dst_path_is_dir = false; + + /* walk a src_path recusively, and resolve path->dst_path for each src */ + list_for_each_entry(s, &m->src_list, list) { + if (mscp_stat(s->path, &ss, src_sftp) < 0) { + pr_err("stat: %s\n", mscp_stat_strerror(src_sftp)); + return -1; + } + src_path_is_dir = mstat_is_dir(ss); + mscp_stat_free(ss); + + INIT_LIST_HEAD(&tmp); + if (walk_src_path(src_sftp, s->path, &tmp) < 0) + return -1; + + if (resolve_dst_path(src_sftp, s->path, m->dst_path, &tmp, + src_path_is_dir, dst_path_is_dir) < 0) + return -1; + + list_splice_tail(&tmp, m->path_list.prev); + } + + if (prepare_chunk(&m->path_list, &m->chunk_list, m->opts->nr_threads, + m->opts->max_chunk_sz, m->opts->min_chunk_sz) < 0) + return -1; + + mscp_free_src_list(m); + + return 0; +} + +int mscp_start(struct mscp *m) +{ + return 0; +} |