diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/file.c | 47 | ||||
-rw-r--r-- | src/main.c | 24 |
2 files changed, 48 insertions, 23 deletions
@@ -324,10 +324,13 @@ static int file_dst_prepare(struct file *f, sftp_session sftp) strncpy(path, f->dst_path, sizeof(path)); + pr_debug("prepare for %s\n", path); + for (p = strchr(path + 1, '/'); p; p = strchr(p + 1, '/')) { *p = '\0'; ret = file_directory_exists(path, sftp); + pr_debug("check %s ret=%d\n", path, ret); if (ret < -1) return -1; if (ret == 1) @@ -479,7 +482,7 @@ int chunk_prepare(struct chunk *c, sftp_session sftp) lock_acquire(&f->lock); /* XXX: is always acquiring lock per-chunk heavy? */ if (f->state == FILE_STATE_INIT) { - if (file_dst_prepare(f, sftp) < 0) { + if (file_dst_prepare(f, f->dst_remote ? sftp : NULL) < 0) { ret = -1; goto out; } @@ -578,11 +581,11 @@ static int chunk_copy_local_to_remote(struct chunk *c, sftp_session sftp, size_t { struct file *f = c->f; char buf[buf_sz]; - size_t remaind; + size_t remaind, remaind2; sftp_file sf = NULL; mode_t mode; int fd = 0; - int ret; + int ret, ret2; if ((fd = chunk_open_local(f->path, O_RDONLY, c->off)) < 0) { ret = -1; @@ -602,12 +605,15 @@ static int chunk_copy_local_to_remote(struct chunk *c, sftp_session sftp, size_t goto out; } - ret = sftp_write(sf, buf, ret); - if (ret < 0) { - pr_err("failed to write to %s: %s\n", f->dst_path, - ssh_get_error(sftp_ssh(sftp))); - ret = -1; - goto out; + for (remaind2 = ret; remaind2 > 0;) { + ret2 = sftp_write(sf, buf + (ret - remaind2), remaind2); + if (ret2 < 2) { + pr_err("failed to write to %s: %s\n", f->dst_path, + ssh_get_error(sftp_ssh(sftp))); + ret = -1; + goto out; + } + remaind2 -= ret; } remaind -= ret; @@ -633,11 +639,11 @@ static int chunk_copy_remote_to_local(struct chunk *c, sftp_session sftp, size_t { struct file *f = c->f; char buf[buf_sz]; - size_t remaind; + size_t remaind, remaind2; sftp_file sf = NULL; mode_t mode; int fd = 0; - int ret; + int ret, ret2; if ((fd = chunk_open_local(f->dst_path, O_WRONLY | O_CREAT, c->off)) < 0) { ret = -1; @@ -650,22 +656,25 @@ static int chunk_copy_remote_to_local(struct chunk *c, sftp_session sftp, size_t } for (remaind = c->len; remaind > 0;) { - ret = sftp_read(sf, buf, ret); + ret = sftp_read(sf, buf, buf_sz); if (ret < 0) { - pr_err("failed to write to %s: %s\n", f->dst_path, + pr_err("failed to read from %s: %s\n", f->dst_path, ssh_get_error(sftp_ssh(sftp))); ret = -1; goto out; } - ret = write(fd, buf, buf_sz); - if (ret < 0) { - pr_err("failed to read %s: %s\n", f->path, strerrno()); - ret = -1; - goto out; + for (remaind2 = ret; remaind2 > 0;) { + ret2 = write(fd, buf + (ret - remaind2), remaind2); + if (ret2 < 2) { + pr_err("failed to write to %s: %s\n", f->dst_path, + strerrno()); + ret = -1; + goto out; + } + remaind2 -= ret; } - remaind -= ret; } @@ -12,7 +12,9 @@ int verbose = 0; /* util.h */ -#define DEFAULT_MIN_CHUNK_SZ (64 << 20) /* 64MB */ +#define DEFAULT_MIN_CHUNK_SZ (64 << 20) /* 64MB */ +#define DEFAULT_BUF_SZ 32768 /* CHANNEL_MAX_PACKET in libssh */ +/* XXX: passing over CHANNEL_MAX_PACKET bytes to sftp_write stalls */ struct sscp { char *host; /* remote host (and username) */ @@ -22,7 +24,9 @@ struct sscp { struct list_head chunk_list; lock chunk_lock; /* lock for chunk list */ - char *target; + char *target; + + int buf_sz; }; void usage(bool print_help) { @@ -39,6 +43,10 @@ void usage(bool print_help) { printf(" -n NR_CONNECTIONS max number of connections (default: # of cpu cores)\n" " -s MIN_CHUNKSIZE min chunk size (default: 64MB)\n" " -S MAX_CHUNKSIZE max chunk size (default: filesize / nr_conn)\n" + " -b BUFFER_SIZE buffer size for read/write (default 32768B)\n" + " Note that this value is derived from\n" + " CHANNEL_MAX_PACKET in libssh. Recommend NOT\n" + " exceeds this value.\n" "\n" " -l LOGIN_NAME login name\n" " -p PORT port number\n" @@ -114,8 +122,9 @@ int main(int argc, char **argv) INIT_LIST_HEAD(&sscp.file_list); INIT_LIST_HEAD(&sscp.chunk_list); lock_init(&sscp.chunk_lock); + sscp.buf_sz = DEFAULT_BUF_SZ; - while ((ch = getopt(argc, argv, "n:s:S:l:p:i:c:Cvh")) != -1) { + while ((ch = getopt(argc, argv, "n:s:S:b:l:p:i:c:Cvh")) != -1) { switch (ch) { case 'n': nr_conn = atoi(optarg); @@ -154,6 +163,13 @@ int main(int argc, char **argv) return -1; } break; + case 'b': + sscp.buf_sz = atoi(optarg); + if (sscp.buf_sz < 1) { + pr_err("invalid buffer size: %s\n", optarg); + return -1; + } + break; case 'l': opts.login_name = optarg; break; @@ -245,7 +261,7 @@ int main(int argc, char **argv) struct chunk *c; list_for_each_entry(c, &sscp.chunk_list, list) { chunk_prepare(c, sscp.ctrl); - chunk_copy(c, sscp.ctrl, 8192); + chunk_copy(c, sscp.ctrl, sscp.buf_sz); } |