diff options
-rw-r--r-- | CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/fileops.c | 310 | ||||
-rw-r--r-- | src/fileops.h | 47 | ||||
-rw-r--r-- | src/message.h | 1 | ||||
-rw-r--r-- | src/mscp.c | 16 | ||||
-rw-r--r-- | src/path.c | 109 | ||||
-rw-r--r-- | src/path.h | 249 |
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> @@ -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; @@ -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", @@ -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_ */ |