version 1.162, 2022/03/31 03:07:03 |
version 1.163, 2022/05/13 06:31:50 |
|
|
int |
int |
do_download(struct sftp_conn *conn, const char *remote_path, |
do_download(struct sftp_conn *conn, const char *remote_path, |
const char *local_path, Attrib *a, int preserve_flag, int resume_flag, |
const char *local_path, Attrib *a, int preserve_flag, int resume_flag, |
int fsync_flag) |
int fsync_flag, int inplace_flag) |
{ |
{ |
struct sshbuf *msg; |
struct sshbuf *msg; |
u_char *handle; |
u_char *handle; |
|
|
&handle, &handle_len) != 0) |
&handle, &handle_len) != 0) |
return -1; |
return -1; |
|
|
local_fd = open(local_path, |
local_fd = open(local_path, O_WRONLY | O_CREAT | |
O_WRONLY | O_CREAT | (resume_flag ? 0 : O_TRUNC), mode | S_IWUSR); |
((resume_flag || inplace_flag) ? 0 : O_TRUNC), mode | S_IWUSR); |
if (local_fd == -1) { |
if (local_fd == -1) { |
error("open local \"%s\": %s", local_path, strerror(errno)); |
error("open local \"%s\": %s", local_path, strerror(errno)); |
goto fail; |
goto fail; |
|
|
static int |
static int |
download_dir_internal(struct sftp_conn *conn, const char *src, const char *dst, |
download_dir_internal(struct sftp_conn *conn, const char *src, const char *dst, |
int depth, Attrib *dirattrib, int preserve_flag, int print_flag, |
int depth, Attrib *dirattrib, int preserve_flag, int print_flag, |
int resume_flag, int fsync_flag, int follow_link_flag) |
int resume_flag, int fsync_flag, int follow_link_flag, int inplace_flag) |
{ |
{ |
int i, ret = 0; |
int i, ret = 0; |
SFTP_DIRENT **dir_entries; |
SFTP_DIRENT **dir_entries; |
|
|
if (download_dir_internal(conn, new_src, new_dst, |
if (download_dir_internal(conn, new_src, new_dst, |
depth + 1, &(dir_entries[i]->a), preserve_flag, |
depth + 1, &(dir_entries[i]->a), preserve_flag, |
print_flag, resume_flag, |
print_flag, resume_flag, |
fsync_flag, follow_link_flag) == -1) |
fsync_flag, follow_link_flag, inplace_flag) == -1) |
ret = -1; |
ret = -1; |
} else if (S_ISREG(dir_entries[i]->a.perm) || |
} else if (S_ISREG(dir_entries[i]->a.perm) || |
(follow_link_flag && S_ISLNK(dir_entries[i]->a.perm))) { |
(follow_link_flag && S_ISLNK(dir_entries[i]->a.perm))) { |
|
|
if (do_download(conn, new_src, new_dst, |
if (do_download(conn, new_src, new_dst, |
S_ISLNK(dir_entries[i]->a.perm) ? NULL : |
S_ISLNK(dir_entries[i]->a.perm) ? NULL : |
&(dir_entries[i]->a), |
&(dir_entries[i]->a), |
preserve_flag, resume_flag, fsync_flag) == -1) { |
preserve_flag, resume_flag, fsync_flag, |
|
inplace_flag) == -1) { |
error("Download of file %s to %s failed", |
error("Download of file %s to %s failed", |
new_src, new_dst); |
new_src, new_dst); |
ret = -1; |
ret = -1; |
|
|
int |
int |
download_dir(struct sftp_conn *conn, const char *src, const char *dst, |
download_dir(struct sftp_conn *conn, const char *src, const char *dst, |
Attrib *dirattrib, int preserve_flag, int print_flag, int resume_flag, |
Attrib *dirattrib, int preserve_flag, int print_flag, int resume_flag, |
int fsync_flag, int follow_link_flag) |
int fsync_flag, int follow_link_flag, int inplace_flag) |
{ |
{ |
char *src_canon; |
char *src_canon; |
int ret; |
int ret; |
|
|
|
|
ret = download_dir_internal(conn, src_canon, dst, 0, |
ret = download_dir_internal(conn, src_canon, dst, 0, |
dirattrib, preserve_flag, print_flag, resume_flag, fsync_flag, |
dirattrib, preserve_flag, print_flag, resume_flag, fsync_flag, |
follow_link_flag); |
follow_link_flag, inplace_flag); |
free(src_canon); |
free(src_canon); |
return ret; |
return ret; |
} |
} |
|
|
int |
int |
do_upload(struct sftp_conn *conn, const char *local_path, |
do_upload(struct sftp_conn *conn, const char *local_path, |
const char *remote_path, int preserve_flag, int resume, int fsync_flag) |
const char *remote_path, int preserve_flag, int resume, |
|
int fsync_flag, int inplace_flag) |
{ |
{ |
int r, local_fd; |
int r, local_fd; |
u_int status = SSH2_FX_OK; |
u_int openmode, id, status = SSH2_FX_OK, reordered = 0; |
u_int id; |
|
u_char type; |
|
off_t offset, progress_counter; |
off_t offset, progress_counter; |
u_char *handle, *data; |
u_char type, *handle, *data; |
struct sshbuf *msg; |
struct sshbuf *msg; |
struct stat sb; |
struct stat sb; |
Attrib a, *c = NULL; |
Attrib a, t, *c = NULL; |
u_int32_t startid; |
u_int32_t startid, ackid; |
u_int32_t ackid; |
u_int64_t highwater = 0; |
struct request *ack = NULL; |
struct request *ack = NULL; |
struct requests acks; |
struct requests acks; |
size_t handle_len; |
size_t handle_len; |
|
|
} |
} |
} |
} |
|
|
|
openmode = SSH2_FXF_WRITE|SSH2_FXF_CREAT; |
|
if (resume) |
|
openmode |= SSH2_FXF_APPEND; |
|
else if (!inplace_flag) |
|
openmode |= SSH2_FXF_TRUNC; |
|
|
/* Send open request */ |
/* Send open request */ |
if (send_open(conn, remote_path, "dest", SSH2_FXF_WRITE|SSH2_FXF_CREAT| |
if (send_open(conn, remote_path, "dest", openmode, &a, |
(resume ? SSH2_FXF_APPEND : SSH2_FXF_TRUNC), |
&handle, &handle_len) != 0) { |
&a, &handle, &handle_len) != 0) { |
|
close(local_fd); |
close(local_fd); |
return -1; |
return -1; |
} |
} |
|
|
ack->id, ack->len, (unsigned long long)ack->offset); |
ack->id, ack->len, (unsigned long long)ack->offset); |
++ackid; |
++ackid; |
progress_counter += ack->len; |
progress_counter += ack->len; |
|
if (!reordered && ack->offset <= highwater) |
|
highwater = ack->offset + ack->len; |
|
else if (!reordered && ack->offset > highwater) { |
|
debug3_f("server reordered ACKs"); |
|
reordered = 1; |
|
} |
free(ack); |
free(ack); |
} |
} |
offset += len; |
offset += len; |
|
|
status = SSH2_FX_FAILURE; |
status = SSH2_FX_FAILURE; |
} |
} |
|
|
|
if ((resume || inplace_flag) && (status != SSH2_FX_OK || interrupted)) { |
|
debug("truncating at %llu", (unsigned long long)highwater); |
|
attrib_clear(&t); |
|
t.flags = SSH2_FILEXFER_ATTR_SIZE; |
|
t.size = highwater; |
|
do_fsetstat(conn, handle, handle_len, &a); |
|
} |
|
|
if (close(local_fd) == -1) { |
if (close(local_fd) == -1) { |
error("close local \"%s\": %s", local_path, strerror(errno)); |
error("close local \"%s\": %s", local_path, strerror(errno)); |
status = SSH2_FX_FAILURE; |
status = SSH2_FX_FAILURE; |
|
|
static int |
static int |
upload_dir_internal(struct sftp_conn *conn, const char *src, const char *dst, |
upload_dir_internal(struct sftp_conn *conn, const char *src, const char *dst, |
int depth, int preserve_flag, int print_flag, int resume, int fsync_flag, |
int depth, int preserve_flag, int print_flag, int resume, int fsync_flag, |
int follow_link_flag) |
int follow_link_flag, int inplace_flag) |
{ |
{ |
int ret = 0; |
int ret = 0; |
DIR *dirp; |
DIR *dirp; |
|
|
|
|
if (upload_dir_internal(conn, new_src, new_dst, |
if (upload_dir_internal(conn, new_src, new_dst, |
depth + 1, preserve_flag, print_flag, resume, |
depth + 1, preserve_flag, print_flag, resume, |
fsync_flag, follow_link_flag) == -1) |
fsync_flag, follow_link_flag, inplace_flag) == -1) |
ret = -1; |
ret = -1; |
} else if (S_ISREG(sb.st_mode) || |
} else if (S_ISREG(sb.st_mode) || |
(follow_link_flag && S_ISLNK(sb.st_mode))) { |
(follow_link_flag && S_ISLNK(sb.st_mode))) { |
if (do_upload(conn, new_src, new_dst, |
if (do_upload(conn, new_src, new_dst, |
preserve_flag, resume, fsync_flag) == -1) { |
preserve_flag, resume, fsync_flag, |
|
inplace_flag) == -1) { |
error("upload \"%s\" to \"%s\" failed", |
error("upload \"%s\" to \"%s\" failed", |
new_src, new_dst); |
new_src, new_dst); |
ret = -1; |
ret = -1; |
|
|
int |
int |
upload_dir(struct sftp_conn *conn, const char *src, const char *dst, |
upload_dir(struct sftp_conn *conn, const char *src, const char *dst, |
int preserve_flag, int print_flag, int resume, int fsync_flag, |
int preserve_flag, int print_flag, int resume, int fsync_flag, |
int follow_link_flag) |
int follow_link_flag, int inplace_flag) |
{ |
{ |
char *dst_canon; |
char *dst_canon; |
int ret; |
int ret; |
|
|
} |
} |
|
|
ret = upload_dir_internal(conn, src, dst_canon, 0, preserve_flag, |
ret = upload_dir_internal(conn, src, dst_canon, 0, preserve_flag, |
print_flag, resume, fsync_flag, follow_link_flag); |
print_flag, resume, fsync_flag, follow_link_flag, inplace_flag); |
|
|
free(dst_canon); |
free(dst_canon); |
return ret; |
return ret; |