mirror of
https://github.com/upa/mscp.git
synced 2026-02-15 09:44:43 +08:00
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.
This commit is contained in:
@@ -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})
|
||||
|
||||
310
src/fileops.c
Normal file
310
src/fileops.c
Normal file
@@ -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;
|
||||
}
|
||||
47
src/fileops.h
Normal file
47
src/fileops.h
Normal file
@@ -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);
|
||||
@@ -2,6 +2,7 @@
|
||||
#define _MESSAGE_H_
|
||||
|
||||
#include <libgen.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <mscp.h>
|
||||
|
||||
|
||||
16
src/mscp.c
16
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;
|
||||
|
||||
|
||||
109
src/path.c
109
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;
|
||||
return append_path(sftp, path, st, path_list, a);
|
||||
}
|
||||
|
||||
if (!mstat_is_dir(s)) {
|
||||
/* not regular file and not directory, skip it. */
|
||||
mscp_stat_free(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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",
|
||||
|
||||
249
src/path.h
249
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_ */
|
||||
|
||||
Reference in New Issue
Block a user