|
Lines 95-100
struct sftp_conn {
Link Here
|
| 95 |
#define SFTP_EXT_FSYNC 0x00000010 |
95 |
#define SFTP_EXT_FSYNC 0x00000010 |
| 96 |
#define SFTP_EXT_LSETSTAT 0x00000020 |
96 |
#define SFTP_EXT_LSETSTAT 0x00000020 |
| 97 |
#define SFTP_EXT_LIMITS 0x00000040 |
97 |
#define SFTP_EXT_LIMITS 0x00000040 |
|
|
98 |
#define SFTP_EXT_COPY_DATA 0x00000080 |
| 98 |
u_int exts; |
99 |
u_int exts; |
| 99 |
u_int64_t limit_kbps; |
100 |
u_int64_t limit_kbps; |
| 100 |
struct bwlimit bwlimit_in, bwlimit_out; |
101 |
struct bwlimit bwlimit_in, bwlimit_out; |
|
Lines 483-488
do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests,
Link Here
|
| 483 |
strcmp((char *)value, "1") == 0) { |
484 |
strcmp((char *)value, "1") == 0) { |
| 484 |
ret->exts |= SFTP_EXT_LIMITS; |
485 |
ret->exts |= SFTP_EXT_LIMITS; |
| 485 |
known = 1; |
486 |
known = 1; |
|
|
487 |
} else if (strcmp(name, "copy-data") == 0 && |
| 488 |
strcmp((char *)value, "1") == 0) { |
| 489 |
ret->exts |= SFTP_EXT_COPY_DATA; |
| 490 |
known = 1; |
| 486 |
} |
491 |
} |
| 487 |
if (known) { |
492 |
if (known) { |
| 488 |
debug2("Server supports extension \"%s\" revision %s", |
493 |
debug2("Server supports extension \"%s\" revision %s", |
|
Lines 971-976
do_realpath(struct sftp_conn *conn, const char *path)
Link Here
|
| 971 |
return(filename); |
976 |
return(filename); |
| 972 |
} |
977 |
} |
| 973 |
|
978 |
|
|
|
979 |
int |
| 980 |
do_copy(struct sftp_conn *conn, const char *oldpath, const char *newpath) |
| 981 |
{ |
| 982 |
Attrib junk, *a; |
| 983 |
struct sshbuf *msg; |
| 984 |
u_char *old_handle, *new_handle; |
| 985 |
u_int mode, status, id; |
| 986 |
size_t old_handle_len, new_handle_len; |
| 987 |
int r; |
| 988 |
|
| 989 |
/* Return if the extension is not supported */ |
| 990 |
if ((conn->exts & SFTP_EXT_COPY_DATA) == 0) { |
| 991 |
error("Server does not support copy-data extension"); |
| 992 |
return -1; |
| 993 |
} |
| 994 |
|
| 995 |
/* Make sure the file exists, and we can copy its perms */ |
| 996 |
if ((a = do_stat(conn, oldpath, 0)) == NULL) |
| 997 |
return -1; |
| 998 |
|
| 999 |
/* Do not preserve set[ug]id here, as we do not preserve ownership */ |
| 1000 |
if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) { |
| 1001 |
mode = a->perm & 0777; |
| 1002 |
|
| 1003 |
if (!S_ISREG(a->perm)) { |
| 1004 |
error("Cannot copy non-regular file: %s", oldpath); |
| 1005 |
return -1; |
| 1006 |
} |
| 1007 |
} else { |
| 1008 |
/* NB: The user's umask will apply to this */ |
| 1009 |
mode = 0666; |
| 1010 |
} |
| 1011 |
|
| 1012 |
/* Set up the new perms for the new file */ |
| 1013 |
attrib_clear(a); |
| 1014 |
a->perm = mode; |
| 1015 |
a->flags |= SSH2_FILEXFER_ATTR_PERMISSIONS; |
| 1016 |
|
| 1017 |
if ((msg = sshbuf_new()) == NULL) |
| 1018 |
fatal("%s: sshbuf_new failed", __func__); |
| 1019 |
|
| 1020 |
attrib_clear(&junk); /* Send empty attributes */ |
| 1021 |
|
| 1022 |
/* Open the old file for reading */ |
| 1023 |
id = conn->msg_id++; |
| 1024 |
if ((r = sshbuf_put_u8(msg, SSH2_FXP_OPEN)) != 0 || |
| 1025 |
(r = sshbuf_put_u32(msg, id)) != 0 || |
| 1026 |
(r = sshbuf_put_cstring(msg, oldpath)) != 0 || |
| 1027 |
(r = sshbuf_put_u32(msg, SSH2_FXF_READ)) != 0 || |
| 1028 |
(r = encode_attrib(msg, &junk)) != 0) |
| 1029 |
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
| 1030 |
send_msg(conn, msg); |
| 1031 |
debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, oldpath); |
| 1032 |
|
| 1033 |
sshbuf_reset(msg); |
| 1034 |
|
| 1035 |
old_handle = get_handle(conn, id, &old_handle_len, |
| 1036 |
"remote open(\"%s\")", oldpath); |
| 1037 |
if (old_handle == NULL) { |
| 1038 |
sshbuf_free(msg); |
| 1039 |
return -1; |
| 1040 |
} |
| 1041 |
|
| 1042 |
/* Open the new file for writing */ |
| 1043 |
id = conn->msg_id++; |
| 1044 |
if ((r = sshbuf_put_u8(msg, SSH2_FXP_OPEN)) != 0 || |
| 1045 |
(r = sshbuf_put_u32(msg, id)) != 0 || |
| 1046 |
(r = sshbuf_put_cstring(msg, newpath)) != 0 || |
| 1047 |
(r = sshbuf_put_u32(msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT| |
| 1048 |
SSH2_FXF_TRUNC)) != 0 || |
| 1049 |
(r = encode_attrib(msg, a)) != 0) |
| 1050 |
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
| 1051 |
send_msg(conn, msg); |
| 1052 |
debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, newpath); |
| 1053 |
|
| 1054 |
sshbuf_reset(msg); |
| 1055 |
|
| 1056 |
new_handle = get_handle(conn, id, &new_handle_len, |
| 1057 |
"remote open(\"%s\")", newpath); |
| 1058 |
if (new_handle == NULL) { |
| 1059 |
sshbuf_free(msg); |
| 1060 |
free(old_handle); |
| 1061 |
return -1; |
| 1062 |
} |
| 1063 |
|
| 1064 |
/* Copy the file data */ |
| 1065 |
id = conn->msg_id++; |
| 1066 |
if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 || |
| 1067 |
(r = sshbuf_put_u32(msg, id)) != 0 || |
| 1068 |
(r = sshbuf_put_cstring(msg, "copy-data")) != 0 || |
| 1069 |
(r = sshbuf_put_string(msg, old_handle, old_handle_len)) != 0 || |
| 1070 |
(r = sshbuf_put_u64(msg, 0)) != 0 || |
| 1071 |
(r = sshbuf_put_u64(msg, 0)) != 0 || |
| 1072 |
(r = sshbuf_put_string(msg, new_handle, new_handle_len)) != 0 || |
| 1073 |
(r = sshbuf_put_u64(msg, 0)) != 0) |
| 1074 |
fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
| 1075 |
send_msg(conn, msg); |
| 1076 |
debug3("Sent message copy-data \"%s\" 0 0 -> \"%s\" 0", |
| 1077 |
oldpath, newpath); |
| 1078 |
|
| 1079 |
status = get_status(conn, id); |
| 1080 |
if (status != SSH2_FX_OK) |
| 1081 |
error("Couldn't copy file \"%s\" to \"%s\": %s", oldpath, |
| 1082 |
newpath, fx2txt(status)); |
| 1083 |
|
| 1084 |
/* Clean up everything */ |
| 1085 |
sshbuf_free(msg); |
| 1086 |
do_close(conn, old_handle, old_handle_len); |
| 1087 |
do_close(conn, new_handle, new_handle_len); |
| 1088 |
free(old_handle); |
| 1089 |
free(new_handle); |
| 1090 |
|
| 1091 |
return status == SSH2_FX_OK ? 0 : -1; |
| 1092 |
} |
| 1093 |
|
| 974 |
int |
1094 |
int |
| 975 |
do_rename(struct sftp_conn *conn, const char *oldpath, const char *newpath, |
1095 |
do_rename(struct sftp_conn *conn, const char *oldpath, const char *newpath, |
| 976 |
int force_legacy) |
1096 |
int force_legacy) |