summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt2
-rw-r--r--src/fileops.c310
-rw-r--r--src/fileops.h47
-rw-r--r--src/message.h1
-rw-r--r--src/mscp.c16
-rw-r--r--src/path.c109
-rw-r--r--src/path.h249
7 files changed, 420 insertions, 314 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ef1fbbc..b19e734 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -62,7 +62,7 @@ if(BUILD_CONAN)
list(APPEND MSCP_LINK_LIBS OpenSSL::Crypto)
endif()
-set(LIBMSCP_SRC src/mscp.c src/ssh.c src/path.c src/platform.c src/message.c)
+set(LIBMSCP_SRC src/mscp.c src/ssh.c src/fileops.c src/path.c src/platform.c src/message.c)
# libmscp.so
add_library(mscp-shared SHARED ${LIBMSCP_SRC})
diff --git a/src/fileops.c b/src/fileops.c
new file mode 100644
index 0000000..7f6ffe4
--- /dev/null
+++ b/src/fileops.c
@@ -0,0 +1,310 @@
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <dirent.h>
+
+#include <fileops.h>
+#include <ssh.h>
+#include <message.h>
+
+
+sftp_session __thread tls_sftp;
+/* tls_sftp is used *_wrapped() functions */
+
+void set_tls_sftp_session(sftp_session sftp)
+{
+ tls_sftp = sftp;
+}
+
+static void sftp_err_to_errno(sftp_session sftp)
+{
+ int sftperr = sftp_get_error(sftp);
+
+ switch (sftperr){
+ case SSH_FX_OK:
+ case SSH_FX_EOF:
+ errno = 0;
+ break;
+ case SSH_FX_NO_SUCH_FILE:
+ case SSH_FX_NO_SUCH_PATH:
+ errno = ENOENT;
+ break;
+ case SSH_FX_PERMISSION_DENIED:
+ errno = EACCES;
+ break;
+ case SSH_FX_FAILURE:
+ errno = EINVAL;
+ case SSH_FX_BAD_MESSAGE:
+ errno = EBADMSG;
+ case SSH_FX_NO_CONNECTION:
+ errno = ENOTCONN;
+ break;
+ case SSH_FX_CONNECTION_LOST:
+ errno = ENETRESET;
+ break;
+ case SSH_FX_OP_UNSUPPORTED:
+ errno = EOPNOTSUPP;
+ break;
+ case SSH_FX_INVALID_HANDLE:
+ errno = EBADF;
+ break;
+ case SSH_FX_FILE_ALREADY_EXISTS:
+ errno = EEXIST;
+ break;
+ case SSH_FX_WRITE_PROTECT:
+ errno = EPERM;
+ break;
+ case SSH_FX_NO_MEDIA:
+ errno = ENODEV;
+ break;
+ default:
+ mpr_warn(stderr, "unkown SSH_FX response %d", sftperr);
+ }
+}
+
+
+MDIR *mscp_opendir(const char *path, sftp_session sftp)
+{
+ MDIR *md;
+
+ if (!(md = malloc(sizeof(*md))))
+ return NULL;
+ memset(md, 0, sizeof(*md));
+
+ if (tls_sftp) {
+ md->remote = sftp_opendir(tls_sftp, path);
+ sftp_err_to_errno(sftp);
+ if (!md->remote) {
+ goto free_out;
+ }
+ } else {
+ md->local = opendir(path);
+ if (!md->local) {
+ goto free_out;
+ }
+ }
+
+ return md;
+
+free_out:
+ free(md);
+ return NULL;
+}
+
+MDIR *mscp_opendir_wrapped(const char *path)
+{
+ return mscp_opendir(path, tls_sftp);
+}
+
+int mscp_closedir(MDIR *md)
+{
+ int ret;
+ if (md->remote) {
+ ret = sftp_closedir(md->remote);
+ if (ret < 0)
+ sftp_err_to_errno(md->remote->sftp);
+ } else
+ ret = closedir(md->local);
+
+ free(md);
+ return ret;
+}
+
+
+struct dirent __thread tls_dirent;
+/* tls_dirent contains dirent converted from sftp_attributes returned
+ * from sftp_readdir(). This trick is derived from openssh's
+ * fudge_readdir() */
+
+struct dirent *mscp_readdir(MDIR *md)
+{
+ sftp_attributes attr;
+ struct dirent *ret = NULL;
+ static int inum = 1;
+
+ if (md->remote) {
+ attr = sftp_readdir(md->remote->sftp, md->remote);
+ if (!attr) {
+ sftp_err_to_errno(md->remote->sftp);
+ return NULL;
+ }
+
+ memset(&tls_dirent, 0, sizeof(tls_dirent));
+ strlcpy(tls_dirent.d_name, attr->name, sizeof(tls_dirent.d_name));
+ tls_dirent.d_ino = inum++;
+ if (!inum)
+ inum = 1;
+ ret = &tls_dirent;
+ sftp_attributes_free(attr);
+ } else
+ ret = readdir(md->local);
+
+ return ret;
+}
+
+int mscp_mkdir(const char *path, mode_t mode, sftp_session sftp)
+{
+ int ret;
+
+ if (sftp) {
+ ret = sftp_mkdir(sftp, path, mode);
+ fprintf(stderr, "after sftp_mkdir(%s), sftp_get_error is %d\n",
+ path, sftp_get_error(sftp));
+ sftp_err_to_errno(sftp);
+ } else
+ ret = mkdir(path, mode);
+
+ if (ret < 0 && errno == EEXIST) {
+ ret = 0;
+ }
+
+ return ret;
+}
+
+
+static void sftp_attr_to_stat(sftp_attributes attr, struct stat *st)
+{
+ memset(st, 0, sizeof(*st));
+ st->st_size = attr->size;
+ st->st_uid = attr->uid;
+ st->st_gid = attr->gid;
+ st->st_mode = attr->permissions;
+
+ switch (attr->type) {
+ case SSH_FILEXFER_TYPE_REGULAR:
+ st->st_mode |= S_IFREG;
+ break;
+ case SSH_FILEXFER_TYPE_DIRECTORY:
+ st->st_mode |= S_IFDIR;
+ break;
+ case SSH_FILEXFER_TYPE_SYMLINK:
+ st->st_mode |= S_IFLNK;
+ break;
+ case SSH_FILEXFER_TYPE_SPECIAL:
+ st->st_mode |= S_IFCHR; /* or block? */
+ break;
+ case SSH_FILEXFER_TYPE_UNKNOWN:
+ st->st_mode |= S_IFIFO; /* really? */
+ break;
+ default:
+ mpr_warn(stderr, "unkown SSH_FILEXFER_TYPE %d", attr->type);
+ }
+
+ /* ToDo: convert atime, ctime, and mtime */
+}
+
+
+int mscp_stat(const char *path, struct stat *st, sftp_session sftp)
+{
+ sftp_attributes attr;
+ int ret = 0;
+
+ if (sftp) {
+ attr = sftp_stat(sftp, path);
+ sftp_err_to_errno(sftp);
+ if (!attr)
+ return -1;
+
+ sftp_attr_to_stat(attr, st);
+ sftp_attributes_free(attr);
+ ret = 0;
+ } else
+ ret = stat(path, st);
+
+ return ret;
+}
+
+int mscp_stat_wrapped(const char *path, struct stat *st)
+{
+ return mscp_stat(path, st, tls_sftp);
+}
+
+int mscp_lstat(const char *path, struct stat *st, sftp_session sftp)
+{
+ sftp_attributes attr;
+ int ret = 0;
+
+ if (sftp) {
+ attr = sftp_lstat(sftp, path);
+ sftp_err_to_errno(sftp);
+ if (!attr)
+ return -1;
+
+ sftp_attr_to_stat(attr, st);
+ sftp_attributes_free(attr);
+ ret = 0;
+ } else
+ ret = lstat(path, st);
+
+ return ret;
+}
+
+int mscp_lstat_wrapped(const char *path, struct stat *st)
+{
+ return mscp_lstat(path, st, tls_sftp);
+}
+
+
+mf *mscp_open(const char *path, int flags, mode_t mode, sftp_session sftp)
+{
+ mf *f;
+
+ f = malloc(sizeof(*f));
+ if (!f)
+ return NULL;
+ memset(f, 0, sizeof(*f));
+
+ if (sftp) {
+ f->remote = sftp_open(sftp, path, flags, mode);
+ if (!f->remote) {
+ sftp_err_to_errno(sftp);
+ goto free_out;
+ }
+ } else {
+ f->local = open(path, flags, mode);
+ if (f->local < 0)
+ goto free_out;
+ }
+
+ return f;
+
+free_out:
+ free(f);
+ return NULL;
+}
+
+void mscp_close(mf *f)
+{
+ if (f->remote)
+ sftp_close(f->remote);
+ if (f->local > 0)
+ close(f->local);
+ free(f);
+}
+
+int mscp_lseek(mf *f, size_t off)
+{
+ int ret;
+
+ if (f->remote) {
+ ret = sftp_seek64(f->remote, off);
+ sftp_err_to_errno(f->remote->sftp);
+ } else
+ ret = lseek(f->local, off, SEEK_SET);
+
+ return ret;
+}
+
+int mscp_chmod(const char *path, mode_t mode, sftp_session sftp)
+{
+ int ret;
+
+ if (sftp) {
+ ret = sftp_chmod(sftp, path, mode);
+ sftp_err_to_errno(sftp);
+ } else
+ ret = chmod(path, mode);
+
+ return ret;
+}
diff --git a/src/fileops.h b/src/fileops.h
new file mode 100644
index 0000000..79eb453
--- /dev/null
+++ b/src/fileops.h
@@ -0,0 +1,47 @@
+
+#include <dirent.h>
+#include <sys/stat.h>
+
+#include <ssh.h>
+
+void set_tls_sftp_session(sftp_session sftp);
+/* sftp_session set by set_tls_sftp_session is sued in
+ mscp_open_wrapped(), mscp_stat_wrapped(), and
+ mscp_lstat_wrapped(). This _wrapped() functions exist for
+ sftp_glob() */
+
+struct mdir_struct {
+ DIR *local;
+ sftp_dir remote;
+};
+typedef struct mdir_struct MDIR;
+
+/* directory operations */
+MDIR *mscp_opendir(const char *path, sftp_session sftp);
+
+MDIR *mscp_opendir_wrapped(const char *path);
+int mscp_closedir(MDIR *md);
+struct dirent *mscp_readdir(MDIR *md);
+
+int mscp_mkdir(const char *path, mode_t mode, sftp_session sftp);
+
+/* stat operations */
+int mscp_stat(const char *path, struct stat *st, sftp_session sftp);
+int mscp_stat_wrapped(const char *path, struct stat *st);
+
+int mscp_lstat(const char *path, struct stat *st, sftp_session sftp);
+int mscp_lstat_wrapped(const char *path, struct stat *st);
+
+
+/* file operations */
+
+struct mf_struct {
+ sftp_file remote;
+ int local;
+};
+typedef struct mf_struct mf;
+
+mf *mscp_open(const char *path, int flags, mode_t mode, sftp_session sftp);
+void mscp_close(mf *f);
+int mscp_lseek(mf *f, size_t off);
+int mscp_chmod(const char *path, mode_t mode, sftp_session sftp);
diff --git a/src/message.h b/src/message.h
index aec5be8..8f444b4 100644
--- a/src/message.h
+++ b/src/message.h
@@ -2,6 +2,7 @@
#define _MESSAGE_H_
#include <libgen.h>
+#include <stdio.h>
#include <mscp.h>
diff --git a/src/mscp.c b/src/mscp.c
index 13ae515..f2a3ae7 100644
--- a/src/mscp.c
+++ b/src/mscp.c
@@ -9,6 +9,7 @@
#include <util.h>
#include <ssh.h>
#include <path.h>
+#include <fileops.h>
#include <atomic.h>
#include <platform.h>
#include <message.h>
@@ -376,7 +377,7 @@ void *mscp_scan_thread(void *arg)
struct list_head tmp;
struct path *p;
struct src *s;
- mstat ss, ds;
+ struct stat ss, ds;
m->ret_scan = 0;
@@ -403,9 +404,8 @@ void *mscp_scan_thread(void *arg)
a.dst_path_should_dir = true;
if (mscp_stat(m->dst_path, &ds, dst_sftp) == 0) {
- if (mstat_is_dir(ds))
+ if (S_ISDIR(ds.st_mode))
a.dst_path_is_dir = true;
- mscp_stat_free(ds);
}
a.cp = &m->cp;
@@ -419,16 +419,14 @@ void *mscp_scan_thread(void *arg)
/* 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) {
- mscp_set_error("stat: %s", mscp_strerror(src_sftp));
- mscp_stat_free(ss);
+ mscp_set_error("stat: %s", strerrno());
goto err_out;
}
/* set path specific args */
a.src_path = s->path;
a.dst_path = m->dst_path;
- a.src_path_is_dir = mstat_is_dir(ss);
- mscp_stat_free(ss);
+ a.src_path_is_dir = S_ISDIR(ss.st_mode);
INIT_LIST_HEAD(&tmp);
if (walk_src_path(src_sftp, s->path, &tmp, &a) < 0)
@@ -647,8 +645,8 @@ void *mscp_copy_thread(void *arg)
pthread_cleanup_pop(1);
if (t->ret < 0)
- mscp_set_error("copy failed: chunk %s 0x%010lx-0x%010lx",
- c->p->path, c->off, c->off + c->len);
+ mpr_err(m->msg_fp, "copy failed: chunk %s 0x%010lx-0x%010lx\n",
+ c->p->path, c->off, c->off + c->len);
return NULL;
diff --git a/src/path.c b/src/path.c
index 7dbb9da..e35ff06 100644
--- a/src/path.c
+++ b/src/path.c
@@ -7,6 +7,7 @@
#include <ssh.h>
#include <util.h>
+#include <fileops.h>
#include <list.h>
#include <atomic.h>
#include <path.h>
@@ -190,7 +191,7 @@ static int resolve_chunk(struct path *p, struct path_resolve_args *a)
return 0;
}
-static int append_path(sftp_session sftp, const char *path, mstat s,
+static int append_path(sftp_session sftp, const char *path, struct stat st,
struct list_head *path_list, struct path_resolve_args *a)
{
struct path *p;
@@ -203,8 +204,8 @@ static int append_path(sftp_session sftp, const char *path, mstat s,
memset(p, 0, sizeof(*p));
INIT_LIST_HEAD(&p->list);
strncpy(p->path, path, PATH_MAX - 1);
- p->size = mstat_size(s);
- p->mode = mstat_mode(s);
+ p->size = st.st_size;
+ p->mode = st.st_mode;
p->state = FILE_STATE_INIT;
lock_init(&p->lock);
@@ -239,48 +240,36 @@ static int walk_path_recursive(sftp_session sftp, const char *path,
struct list_head *path_list, struct path_resolve_args *a)
{
char next_path[PATH_MAX];
- mdirent *e;
- mdir *d;
- mstat s;
+ struct dirent *e;
+ struct stat st;
+ MDIR *d;
int ret;
- if (mscp_stat(path, &s, sftp) < 0)
+ if (mscp_stat(path, &st, sftp) < 0)
return -1;
- if (mstat_is_regular(s)) {
+ if (S_ISREG(st.st_mode)) {
/* this path is regular file. it is to be copied */
- ret = append_path(sftp, path, s, path_list, a);
- mscp_stat_free(s);
- return ret;
- }
-
- if (!mstat_is_dir(s)) {
- /* not regular file and not directory, skip it. */
- mscp_stat_free(s);
- return 0;
+ return append_path(sftp, path, st, path_list, a);
}
- mscp_stat_free(s);
-
+ if (!S_ISDIR(st.st_mode))
+ return 0; /* not a regular file and not a directory, skip it. */
/* ok, this path is directory. walk it. */
if (!(d = mscp_opendir(path, sftp)))
return -1;
- for (e = mscp_readdir(d); !mdirent_is_null(e); e = mscp_readdir(d)) {
- if (check_path_should_skip(mdirent_name(e))) {
- mscp_dirent_free(e);
+ for (e = mscp_readdir(d); e; e = mscp_readdir(d)) {
+ if (check_path_should_skip(e->d_name))
continue;
- }
- if (strlen(path) + 1 + strlen(mdirent_name(e)) > PATH_MAX) {
- mscp_set_error("too long path: %s/%s", path, mdirent_name(e));
- mscp_dirent_free(e);
+ if (strlen(path) + 1 + strlen(e->d_name) > PATH_MAX) {
+ mscp_set_error("too long path: %s/%s", path, e->d_name);
return -1;
}
- snprintf(next_path, sizeof(next_path), "%s/%s", path, mdirent_name(e));
+ snprintf(next_path, sizeof(next_path), "%s/%s", path, e->d_name);
ret = walk_path_recursive(sftp, next_path, path_list, a);
- mscp_dirent_free(e);
if (ret < 0)
return ret;
}
@@ -314,10 +303,11 @@ static int touch_dst_path(struct path *p, sftp_session sftp)
{
/* XXX: should reflect the permission of the original directory? */
mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
+ struct stat st;
char path[PATH_MAX];
char *needle;
int ret;
- mfh h;
+ mf *f;
strncpy(path, p->dst_path, sizeof(path));
@@ -326,22 +316,17 @@ static int touch_dst_path(struct path *p, sftp_session sftp)
for (needle = strchr(path + 1, '/'); needle; needle = strchr(needle + 1, '/')) {
*needle = '\0';
- mstat s;
- if (mscp_stat(path, &s, sftp) == 0) {
- if (mstat_is_dir(s)) {
- mscp_stat_free(s);
+ if (mscp_stat(path, &st, sftp) == 0) {
+ if (S_ISDIR(st.st_mode))
goto next; /* directory exists. go deeper */
- } else {
- mscp_stat_free(s);
+ else
return -1; /* path exists, but not directory. */
- }
}
- if (mscp_stat_check_err_noent(sftp) == 0) {
+ if (errno == ENOENT) {
/* no file on the path. create directory. */
if (mscp_mkdir(path, mode, sftp) < 0) {
- mscp_set_error("mkdir %s: %s", path,
- mscp_strerror(sftp));
+ mscp_set_error("mscp_mkdir %s: %s", path, strerrno());
return -1;
}
}
@@ -350,11 +335,13 @@ static int touch_dst_path(struct path *p, sftp_session sftp)
}
/* open file with O_TRUNC to set file size 0 */
- h = mscp_open(p->dst_path, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR, 0, sftp);
- if (mscp_open_is_failed(h))
+ f = mscp_open(p->dst_path, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR, sftp);
+ if (!f) {
+ mscp_set_error("mscp_open %s: %s\n", p->dst_path, strerrno());
return -1;
+ }
- mscp_close(h);
+ mscp_close(f);
return 0;
}
@@ -518,16 +505,16 @@ static int copy_chunk_r2l(struct chunk *c, sftp_file sf, int fd,
return 0;
}
-static int _copy_chunk(struct chunk *c, mfh s, mfh d,
+static int _copy_chunk(struct chunk *c, mf *s, mf *d,
int nr_ahead, int buf_sz, size_t *counter)
{
- if (s.fd > 0 && d.sf) /* local to remote copy */
- return copy_chunk_l2r(c, s.fd, d.sf, nr_ahead, buf_sz, counter);
- else if (s.sf && d.fd > 0) /* remote to local copy */
- return copy_chunk_r2l(c, s.sf, d.fd, nr_ahead, buf_sz, counter);
+ if (s->local && d->remote) /* local to remote copy */
+ return copy_chunk_l2r(c, s->local, d->remote, nr_ahead, buf_sz, counter);
+ else if (s->remote && d->local) /* remote to local copy */
+ return copy_chunk_r2l(c, s->remote, d->local, nr_ahead, buf_sz, counter);
- assert(true); /* not reached */
- return -1;
+ assert(false);
+ return -1; /* not reached */
}
int copy_chunk(FILE *msg_fp, struct chunk *c,
@@ -536,7 +523,7 @@ int copy_chunk(FILE *msg_fp, struct chunk *c,
{
mode_t mode;
int flags;
- mfh s, d;
+ mf *s, *d;
int ret;
assert((src_sftp && !dst_sftp) || (!src_sftp && dst_sftp));
@@ -547,21 +534,33 @@ int copy_chunk(FILE *msg_fp, struct chunk *c,
/* open src */
flags = O_RDONLY;
mode = S_IRUSR;
- s = mscp_open(c->p->path, flags, mode, c->off, src_sftp);
- if (mscp_open_is_failed(s)) {
- mscp_close(d);
+ s = mscp_open(c->p->path, flags, mode, src_sftp);
+ if (!s) {
+ mscp_set_error("mscp_open: %s: %s", c->p->path, strerrno());
+ return -1;
+ }
+ if (mscp_lseek(s, c->off) < 0) {
+ mscp_set_error("mscp_lseek: %s: %s", c->p->path, strerrno());
return -1;
}
/* open dst */
flags = O_WRONLY;
mode = S_IRUSR|S_IWUSR;
- d = mscp_open(c->p->dst_path, flags, mode, c->off, dst_sftp);
- if (mscp_open_is_failed(d))
+ d = mscp_open(c->p->dst_path, flags, mode, dst_sftp);
+ if (!d) {
+ mscp_close(s);
+ mscp_set_error("mscp_open: %s: %s", c->p->dst_path, strerrno());
return -1;
+ }
+ if (mscp_lseek(d, c->off) < 0) {
+ mscp_set_error("mscp_lseek: %s: %s", c->p->dst_path, strerrno());
+ return -1;
+ }
mpr_debug(msg_fp, "copy chunk start: %s 0x%lx-0x%lx\n",
c->p->path, c->off, c->off + c->len);
+
ret = _copy_chunk(c, s, d, nr_ahead, buf_sz, counter);
mpr_debug(msg_fp, "copy chunk done: %s 0x%lx-0x%lx\n",
diff --git a/src/path.h b/src/path.h
index c397a08..5fc08a0 100644
--- a/src/path.h
+++ b/src/path.h
@@ -98,253 +98,4 @@ int copy_chunk(FILE *msg_fp, struct chunk *c,
/* just print contents. just for debugging */
void path_dump(struct list_head *path_list);
-
-
-/* wrap DIR/dirent and sftp_dir/sftp_attribute. not thread safe */
-struct mscp_dir {
- DIR *l;
- sftp_dir r;
- sftp_session sftp;
-};
-typedef struct mscp_dir mdir;
-
-struct mscp_dirent {
- struct dirent *l;
- sftp_attributes r;
-};
-typedef struct mscp_dirent mdirent;
-
-#define mdirent_name(e) ((e->l) ? e->l->d_name : e->r->name)
-#define mdirent_is_dir(e) ((e->l) ? \
- (e->l->d_type == DT_DIR) : \
- (e->r->type == SSH_FILEXFER_TYPE_DIRECTORY))
-#define mdirent_is_null(e) (e->l == NULL && e->r == NULL)
-
-static mdir *mscp_opendir(const char *path, sftp_session sftp)
-{
- mdir *d;
-
- if (!(d = malloc(sizeof(*d))))
- return NULL;
- memset(d, 0, sizeof(*d));
-
- d->sftp = sftp;
-
- if (sftp) {
- d->r = sftp_opendir(sftp, path);
- if (!d->r) {
- mscp_set_error("sftp_opendir '%s': %s",
- path, sftp_get_ssh_error(sftp));
- free(d);
- return NULL;
- }
- } else {
- d->l = opendir(path);
- if (!d->l) {
- mscp_set_error("opendir '%s': %s", path, strerrno());
- free(d);
- return NULL;
- }
- }
- return d;
-}
-
-static int mscp_closedir(mdir *d)
-{
- int ret;
- if (d->r)
- ret = sftp_closedir(d->r);
- else
- ret = closedir(d->l);
- free(d);
- return ret;
-}
-
-static mdirent *mscp_readdir(mdir *d)
-{
- static mdirent e;
-
- memset(&e, 0, sizeof(e));
- if (d->r)
- e.r = sftp_readdir(d->sftp, d->r);
- else
- e.l = readdir(d->l);
- return &e;
-}
-
-static void mscp_dirent_free(mdirent *e)
-{
- if (e->r) {
- sftp_attributes_free(e->r);
- e->r = NULL;
- }
-}
-
-/* wrap retriving error */
-static const char *mscp_strerror(sftp_session sftp)
-{
- if (sftp)
- return sftp_get_ssh_error(sftp);
- return strerrno();
-}
-
-/* warp stat/sftp_stat */
-struct mscp_stat {
- struct stat l;
- sftp_attributes r;
-};
-typedef struct mscp_stat mstat;
-
-static int mscp_stat(const char *path, mstat *s, sftp_session sftp)
-{
- memset(s, 0, sizeof(*s));
-
- if (sftp) {
- s->r = sftp_stat(sftp, path);
- if (!s->r) {
- mscp_set_error("sftp_stat: %s %s",
- sftp_get_ssh_error(sftp), path);
- return -1;
- }
- } else {
- if (stat(path, &s->l) < 0) {
- mscp_set_error("stat: %s %s", strerrno(), path);
- return -1;
- }
- }
-
- return 0;
-}
-
-static int mscp_stat_check_err_noent(sftp_session sftp)
-{
- if (sftp) {
- if (sftp_get_error(sftp) == SSH_FX_NO_SUCH_PATH ||
- sftp_get_error(sftp) == SSH_FX_NO_SUCH_FILE)
- return 0;
- } else {
- if (errno == ENOENT)
- return 0;
- }
- return -1;
-}
-
-static void mscp_stat_free(mstat s) {
- if (s.r)
- sftp_attributes_free(s.r);
-}
-
-#define mstat_size(s) ((s.r) ? s.r->size : s.l.st_size)
-#define mstat_mode(s) ((s.r) ? \
- s.r->permissions : \
- s.l.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO))
-#define mstat_is_regular(s) ((s.r) ? \
- (s.r->type == SSH_FILEXFER_TYPE_REGULAR) : \
- S_ISREG(s.l.st_mode))
-#define mstat_is_dir(s) ((s.r) ? \
- (s.r->type == SSH_FILEXFER_TYPE_DIRECTORY) : \
- S_ISDIR(s.l.st_mode))
-
-/* wrap mkdir */
-static int mscp_mkdir(const char *path, mode_t mode, sftp_session sftp)
-{
- int ret;
-
- if (sftp) {
- ret = sftp_mkdir(sftp, path, mode);
- if (ret < 0 &&
- sftp_get_error(sftp) != SSH_FX_FILE_ALREADY_EXISTS) {
- mscp_set_error("sftp_mkdir '%s': %s",
- path, sftp_get_ssh_error(sftp));
- return -1;
- }
- } else {
- if (mkdir(path, mode) == -1 && errno != EEXIST) {
- mscp_set_error("mkdir '%s': %s", path, strerrno());
- return -1;
- }
- }
-
- return 0;
-}
-
-/* wrap open/sftp_open */
-struct mscp_file_handle {
- int fd;
- sftp_file sf;
-};
-typedef struct mscp_file_handle mfh;
-
-static mfh mscp_open(const char *path, int flags, mode_t mode, size_t off,
- sftp_session sftp)
-{
- mfh h;
-
- h.fd = -1;
- h.sf = NULL;
-
- if (sftp) {
- h.sf = sftp_open(sftp, path, flags, mode);
- if (!h.sf) {
- mscp_set_error("sftp_open '%s': %s",
- path, sftp_get_ssh_error(sftp));
- return h;
- }
-
- if (sftp_seek64(h.sf, off) < 0) {
- mscp_set_error("sftp_seek64 '%s': %s",
- path, sftp_get_ssh_error(sftp));
- sftp_close(h.sf);
- h.sf = NULL;
- return h;
- }
- } else {
- h.fd = open(path, flags, mode);
- if (h.fd < 0) {
- mscp_set_error("open '%s': %s", path, strerrno());
- return h;
- }
- if (lseek(h.fd, off, SEEK_SET) < 0) {
- mscp_set_error("lseek '%s': %s", path, strerrno());
- close(h.fd);
- h.fd = -1;
- return h;
- }
- }
-
- return h;
-}
-
-#define mscp_open_is_failed(h) (h.fd < 0 && h.sf == NULL)
-
-static void mscp_close(mfh h)
-{
- if (h.sf)
- sftp_close(h.sf);
- if (h.fd > 0)
- close(h.fd);
- h.sf = NULL;
- h.fd = -1;
-}
-
-/* wrap chmod/sftp_chmod */
-
-static int mscp_chmod(const char *path, mode_t mode, sftp_session sftp)
-{
- if (sftp) {
- if (sftp_chmod(sftp, path, mode) < 0) {
- mscp_set_error("sftp_chmod '%s': %s",
- path, sftp_get_ssh_error(sftp));
- return -1;
- }
- } else {
- if (chmod(path, mode) < 0) {
- mscp_set_error("chmod '%s': %s", path, strerrno());
- return -1;
- }
- }
-
- return 0;
-}
-
#endif /* _PATH_H_ */