diff options
Diffstat (limited to 'src/path.h')
-rw-r--r-- | src/path.h | 192 |
1 files changed, 192 insertions, 0 deletions
diff --git a/src/path.h b/src/path.h new file mode 100644 index 0000000..3cc5327 --- /dev/null +++ b/src/path.h @@ -0,0 +1,192 @@ +#ifndef _PATH_H_ +#define _PATH_H_ + +#include <limits.h> +#include <fcntl.h> +#include <dirent.h> +#include <sys/stat.h> + +#include <list.h> +#include <atomic.h> +#include <ssh.h> + +struct path { + struct list_head list; /* mscp->path_list */ + + char path[PATH_MAX]; /* file path */ + size_t size; /* size of file on this path */ + mode_t mode; /* permission */ + + char dst_path[PATH_MAX]; /* copy dst path */ + + int state; + lock lock; + refcnt refcnt; +}; +#define FILE_STATE_INIT 0 +#define FILE_STATE_OPENED 1 +#define FILE_STATE_DONE 2 + +struct chunk { + struct list_head list; /* mscp->chunk_list */ + + struct path *p; + size_t off; /* offset of this chunk on the file on path p */ + size_t len; /* length of this chunk */ + size_t done; /* copied bytes for this chunk by a thread */ +}; + + + +/* recursivly walk through src_path and fill path_list for each file */ +int walk_src_path(sftp_session sftp, const char *src_path, struct list_head *path_list); + +/* fill path->dst_path for all files */ +int resolve_dst_path(sftp_session sftp, const char *src_path, const char *dst_path, + struct list_head *path_list, + bool src_path_is_dir, bool dst_path_is_dir); + +/* prepare chunk_list for files in the path_list */ +int prepare_chunk(struct list_head *path_list, struct list_head *chunk_list, + int nr_conn, int min_chunk_sz, int max_chunk_sz); + +/* just print contents. just for debugging */ +void path_dump(struct list_head *path_list); +void chunk_dump(struct list_head *chunk_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) { + pr_err("sftp_opendir: %s: %s\n", path, sftp_get_ssh_error(sftp)); + free(d); + return NULL; + } + } else { + d->l = opendir(path); + if (!d->l) { + pr_err("opendir: %s: %s\n", 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; +} + +/* 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) + return -1; + } else { + if (stat(path, &s->l) < 0) + return -1; + } + + return 0; +} + +static const char *mscp_stat_strerror(sftp_session sftp) +{ + if (sftp) + return sftp_get_ssh_error(sftp); + return strerrno(); +} + +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)) + + + +#endif /* _PATH_H_ */ |