View | Details | Raw Unified | Return to bug 2948 | Differences between
and this patch

Collapse All | Expand All

(-)a/sftp-client.c (+120 lines)
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)
(-)a/sftp-client.h (+3 lines)
Lines 114-119 int do_statvfs(struct sftp_conn *, const char *, struct sftp_statvfs *, int); Link Here
114
/* Rename 'oldpath' to 'newpath' */
114
/* Rename 'oldpath' to 'newpath' */
115
int do_rename(struct sftp_conn *, const char *, const char *, int force_legacy);
115
int do_rename(struct sftp_conn *, const char *, const char *, int force_legacy);
116
116
117
/* Copy 'oldpath' to 'newpath' */
118
int do_copy(struct sftp_conn *, const char *, const char *);
119
117
/* Link 'oldpath' to 'newpath' */
120
/* Link 'oldpath' to 'newpath' */
118
int do_hardlink(struct sftp_conn *, const char *, const char *);
121
int do_hardlink(struct sftp_conn *, const char *, const char *);
119
122
(-)a/sftp.1 (-1 / +13 lines)
Lines 144-150 will abort if any of the following Link Here
144
commands fail:
144
commands fail:
145
.Ic get , put , reget , reput , rename , ln ,
145
.Ic get , put , reget , reput , rename , ln ,
146
.Ic rm , mkdir , chdir , ls ,
146
.Ic rm , mkdir , chdir , ls ,
147
.Ic lchdir , chmod , chown ,
147
.Ic lchdir , copy , cp , chmod , chown ,
148
.Ic chgrp , lpwd , df , symlink ,
148
.Ic chgrp , lpwd , df , symlink ,
149
and
149
and
150
.Ic lmkdir .
150
.Ic lmkdir .
Lines 401-406 If the Link Here
401
flag is specified, then symlinks will not be followed.
401
flag is specified, then symlinks will not be followed.
402
Note that this is only supported by servers that implement
402
Note that this is only supported by servers that implement
403
the "lsetstat@openssh.com" extension.
403
the "lsetstat@openssh.com" extension.
404
.It Ic copy Ar oldpath Ar newpath
405
Copy remote file from
406
.Ar oldpath
407
to
408
.Ar newpath .
409
.Pp
410
Note that this is only supported by servers that implement the "copy-data"
411
extension.
412
.It Ic cp Ar oldpath Ar newpath
413
Alias to
414
.Ic copy
415
command.
404
.It Xo Ic df
416
.It Xo Ic df
405
.Op Fl hi
417
.Op Fl hi
406
.Op Ar path
418
.Op Ar path
(-)a/sftp.c (-1 / +14 lines)
Lines 138-143 enum sftp_command { Link Here
138
	I_CHGRP,
138
	I_CHGRP,
139
	I_CHMOD,
139
	I_CHMOD,
140
	I_CHOWN,
140
	I_CHOWN,
141
	I_COPY,
141
	I_DF,
142
	I_DF,
142
	I_GET,
143
	I_GET,
143
	I_HELP,
144
	I_HELP,
Lines 181-186 static const struct CMD cmds[] = { Link Here
181
	{ "chgrp",	I_CHGRP,	REMOTE	},
182
	{ "chgrp",	I_CHGRP,	REMOTE	},
182
	{ "chmod",	I_CHMOD,	REMOTE	},
183
	{ "chmod",	I_CHMOD,	REMOTE	},
183
	{ "chown",	I_CHOWN,	REMOTE	},
184
	{ "chown",	I_CHOWN,	REMOTE	},
185
	{ "copy",	I_COPY,		REMOTE	},
186
	{ "cp",		I_COPY,		REMOTE	},
184
	{ "df",		I_DF,		REMOTE	},
187
	{ "df",		I_DF,		REMOTE	},
185
	{ "dir",	I_LS,		REMOTE	},
188
	{ "dir",	I_LS,		REMOTE	},
186
	{ "exit",	I_QUIT,		NOARGS	},
189
	{ "exit",	I_QUIT,		NOARGS	},
Lines 280-285 help(void) Link Here
280
	    "chgrp [-h] grp path                Change group of file 'path' to 'grp'\n"
283
	    "chgrp [-h] grp path                Change group of file 'path' to 'grp'\n"
281
	    "chmod [-h] mode path               Change permissions of file 'path' to 'mode'\n"
284
	    "chmod [-h] mode path               Change permissions of file 'path' to 'mode'\n"
282
	    "chown [-h] own path                Change owner of file 'path' to 'own'\n"
285
	    "chown [-h] own path                Change owner of file 'path' to 'own'\n"
286
	    "copy oldpath newpath               Copy remote file\n"
287
	    "cp oldpath newpath                 Copy remote file\n"
283
	    "df [-hi] [path]                    Display statistics for current directory or\n"
288
	    "df [-hi] [path]                    Display statistics for current directory or\n"
284
	    "                                   filesystem containing 'path'\n"
289
	    "                                   filesystem containing 'path'\n"
285
	    "exit                               Quit sftp\n"
290
	    "exit                               Quit sftp\n"
Lines 1361-1366 parse_args(const char **cpp, int *ignore_errors, int *disable_echo, int *aflag, Link Here
1361
		if ((optidx = parse_link_flags(cmd, argv, argc, sflag)) == -1)
1366
		if ((optidx = parse_link_flags(cmd, argv, argc, sflag)) == -1)
1362
			return -1;
1367
			return -1;
1363
		goto parse_two_paths;
1368
		goto parse_two_paths;
1369
	case I_COPY:
1370
		if ((optidx = parse_no_flags(cmd, argv, argc)) == -1)
1371
			return -1;
1372
		goto parse_two_paths;
1364
	case I_RENAME:
1373
	case I_RENAME:
1365
		if ((optidx = parse_rename_flags(cmd, argv, argc, lflag)) == -1)
1374
		if ((optidx = parse_rename_flags(cmd, argv, argc, lflag)) == -1)
1366
			return -1;
1375
			return -1;
Lines 1528-1533 parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, Link Here
1528
		err = process_put(conn, path1, path2, *pwd, pflag,
1537
		err = process_put(conn, path1, path2, *pwd, pflag,
1529
		    rflag, aflag, fflag);
1538
		    rflag, aflag, fflag);
1530
		break;
1539
		break;
1540
	case I_COPY:
1541
		path1 = make_absolute(path1, *pwd);
1542
		path2 = make_absolute(path2, *pwd);
1543
		err = do_copy(conn, path1, path2);
1544
		break;
1531
	case I_RENAME:
1545
	case I_RENAME:
1532
		path1 = make_absolute(path1, *pwd);
1546
		path1 = make_absolute(path1, *pwd);
1533
		path2 = make_absolute(path2, *pwd);
1547
		path2 = make_absolute(path2, *pwd);
1534
- 

Return to bug 2948