|
Lines 86-91
struct sftp_conn {
Link Here
|
| 86 |
#define SFTP_EXT_FSTATVFS 0x00000004 |
86 |
#define SFTP_EXT_FSTATVFS 0x00000004 |
| 87 |
#define SFTP_EXT_HARDLINK 0x00000008 |
87 |
#define SFTP_EXT_HARDLINK 0x00000008 |
| 88 |
#define SFTP_EXT_FSYNC 0x00000010 |
88 |
#define SFTP_EXT_FSYNC 0x00000010 |
|
|
89 |
#define SFTP_EXT_COPY_DATA 0x00000020 |
| 89 |
u_int exts; |
90 |
u_int exts; |
| 90 |
u_int64_t limit_kbps; |
91 |
u_int64_t limit_kbps; |
| 91 |
struct bwlimit bwlimit_in, bwlimit_out; |
92 |
struct bwlimit bwlimit_in, bwlimit_out; |
|
Lines 463-468
do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests,
Link Here
|
| 463 |
strcmp((char *)value, "1") == 0) { |
464 |
strcmp((char *)value, "1") == 0) { |
| 464 |
ret->exts |= SFTP_EXT_FSYNC; |
465 |
ret->exts |= SFTP_EXT_FSYNC; |
| 465 |
known = 1; |
466 |
known = 1; |
|
|
467 |
} else if (strcmp(name, "copy-data") == 0 && |
| 468 |
strcmp((char *)value, "1") == 0) { |
| 469 |
ret->exts |= SFTP_EXT_COPY_DATA; |
| 470 |
known = 1; |
| 466 |
} |
471 |
} |
| 467 |
if (known) { |
472 |
if (known) { |
| 468 |
debug2("Server supports extension \"%s\" revision %s", |
473 |
debug2("Server supports extension \"%s\" revision %s", |
|
Lines 879-884
do_realpath(struct sftp_conn *conn, const char *path)
Link Here
|
| 879 |
return(filename); |
884 |
return(filename); |
| 880 |
} |
885 |
} |
| 881 |
|
886 |
|
|
|
887 |
int |
| 888 |
do_copy(struct sftp_conn *conn, const char *oldpath, const char *newpath) |
| 889 |
{ |
| 890 |
Attrib junk, *a; |
| 891 |
struct sshbuf *msg; |
| 892 |
u_char *old_handle, *new_handle; |
| 893 |
u_int mode, status, id; |
| 894 |
size_t old_handle_len, new_handle_len; |
| 895 |
int r; |
| 896 |
|
| 897 |
/* Silently return if the extension is not supported */ |
| 898 |
if ((conn->exts & SFTP_EXT_COPY_DATA) == 0) { |
| 899 |
error("Server does not support copy-data extension"); |
| 900 |
return -1; |
| 901 |
} |
| 902 |
|
| 903 |
/* Make sure the file exists, and we can copy its perms */ |
| 904 |
if ((a = do_stat(conn, oldpath, 0)) == NULL) |
| 905 |
return -1; |
| 906 |
|
| 907 |
/* Do not preserve set[ug]id here, as we do not preserve ownership */ |
| 908 |
if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) { |
| 909 |
mode = a->perm & 0777; |
| 910 |
|
| 911 |
if (!S_ISREG(a->perm)) { |
| 912 |
error("Cannot copy non-regular file: %s", oldpath); |
| 913 |
return -1; |
| 914 |
} |
| 915 |
} else { |
| 916 |
mode = 0666; |
| 917 |
} |
| 918 |
|
| 919 |
/* Set up the new perms for the new file */ |
| 920 |
attrib_clear(a); |
| 921 |
a->perm = mode; |
| 922 |
a->flags |= SSH2_FILEXFER_ATTR_PERMISSIONS; |
| 923 |
|
| 924 |
if ((msg = sshbuf_new()) == NULL) |
| 925 |
fatal("%s: sshbuf_new failed", __func__); |
| 926 |
|
| 927 |
attrib_clear(&junk); /* Send empty attributes */ |
| 928 |
|
| 929 |
/* Open the old file for reading */ |
| 930 |
id = conn->msg_id++; |
| 931 |
if ((r = sshbuf_put_u8(msg, SSH2_FXP_OPEN)) != 0 || |
| 932 |
(r = sshbuf_put_u32(msg, id)) != 0 || |
| 933 |
(r = sshbuf_put_cstring(msg, oldpath)) != 0 || |
| 934 |
(r = sshbuf_put_u32(msg, SSH2_FXF_READ)) != 0 || |
| 935 |
(r = encode_attrib(msg, &junk)) != 0) |
| 936 |
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
| 937 |
send_msg(conn, msg); |
| 938 |
debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, oldpath); |
| 939 |
|
| 940 |
sshbuf_reset(msg); |
| 941 |
|
| 942 |
old_handle = get_handle(conn, id, &old_handle_len, |
| 943 |
"remote open(\"%s\")", oldpath); |
| 944 |
if (old_handle == NULL) { |
| 945 |
sshbuf_free(msg); |
| 946 |
return -1; |
| 947 |
} |
| 948 |
|
| 949 |
/* Open the new file for writing */ |
| 950 |
id = conn->msg_id++; |
| 951 |
if ((r = sshbuf_put_u8(msg, SSH2_FXP_OPEN)) != 0 || |
| 952 |
(r = sshbuf_put_u32(msg, id)) != 0 || |
| 953 |
(r = sshbuf_put_cstring(msg, newpath)) != 0 || |
| 954 |
(r = sshbuf_put_u32(msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT| |
| 955 |
SSH2_FXF_TRUNC)) != 0 || |
| 956 |
(r = encode_attrib(msg, a)) != 0) |
| 957 |
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
| 958 |
send_msg(conn, msg); |
| 959 |
debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, newpath); |
| 960 |
|
| 961 |
sshbuf_reset(msg); |
| 962 |
|
| 963 |
new_handle = get_handle(conn, id, &new_handle_len, |
| 964 |
"remote open(\"%s\")", newpath); |
| 965 |
if (new_handle == NULL) { |
| 966 |
sshbuf_free(msg); |
| 967 |
return -1; |
| 968 |
} |
| 969 |
|
| 970 |
/* Copy the file data */ |
| 971 |
id = conn->msg_id++; |
| 972 |
if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 || |
| 973 |
(r = sshbuf_put_u32(msg, id)) != 0 || |
| 974 |
(r = sshbuf_put_cstring(msg, "copy-data")) != 0 || |
| 975 |
(r = sshbuf_put_string(msg, old_handle, old_handle_len)) != 0 || |
| 976 |
(r = sshbuf_put_u64(msg, 0)) != 0 || |
| 977 |
(r = sshbuf_put_u64(msg, 0)) != 0 || |
| 978 |
(r = sshbuf_put_string(msg, new_handle, new_handle_len)) != 0 || |
| 979 |
(r = sshbuf_put_u64(msg, 0)) != 0) |
| 980 |
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
| 981 |
send_msg(conn, msg); |
| 982 |
debug3("Sent message copy-data \"%s\" 0 0 -> \"%s\" 0", |
| 983 |
oldpath, newpath); |
| 984 |
|
| 985 |
status = get_status(conn, id); |
| 986 |
if (status != SSH2_FX_OK) |
| 987 |
error("Couldn't copy file \"%s\" to \"%s\": %s", oldpath, |
| 988 |
newpath, fx2txt(status)); |
| 989 |
|
| 990 |
/* Clean up everything */ |
| 991 |
sshbuf_free(msg); |
| 992 |
do_close(conn, old_handle, old_handle_len); |
| 993 |
do_close(conn, new_handle, new_handle_len); |
| 994 |
free(old_handle); |
| 995 |
free(new_handle); |
| 996 |
|
| 997 |
return status == SSH2_FX_OK ? 0 : -1; |
| 998 |
} |
| 999 |
|
| 882 |
int |
1000 |
int |
| 883 |
do_rename(struct sftp_conn *conn, const char *oldpath, const char *newpath, |
1001 |
do_rename(struct sftp_conn *conn, const char *oldpath, const char *newpath, |
| 884 |
int force_legacy) |
1002 |
int force_legacy) |