summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyo Nakamura <upa@haeena.net>2023-08-03 17:07:39 +0900
committerRyo Nakamura <upa@haeena.net>2023-08-03 17:07:39 +0900
commit9f7c135b1515ae297b839f54ea08c1fd16c9521e (patch)
tree74dc98867f35b76e458939f7846f9fa0c7625eff
parent8ab06c95319d4da360e3ca1c98876902736243b8 (diff)
cleanup wrappers for file operations
Previously wrapper functions for open(), opendir(), and stat(), etc, are implemneted in path.h, and now they are in fileops.h and fileops.c. This commit is a reparation for remote glob.
-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_ */