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

Collapse All | Expand All

(-)a/sftp-client.c (+118 lines)
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)
(-)a/sftp-client.h (+3 lines)
Lines 100-105 int do_statvfs(struct sftp_conn *, const char *, struct sftp_statvfs *, int); Link Here
100
/* Rename 'oldpath' to 'newpath' */
100
/* Rename 'oldpath' to 'newpath' */
101
int do_rename(struct sftp_conn *, const char *, const char *, int force_legacy);
101
int do_rename(struct sftp_conn *, const char *, const char *, int force_legacy);
102
102
103
/* Copy 'oldpath' to 'newpath' */
104
int do_copy(struct sftp_conn *, const char *, const char *);
105
103
/* Link 'oldpath' to 'newpath' */
106
/* Link 'oldpath' to 'newpath' */
104
int do_hardlink(struct sftp_conn *, const char *, const char *);
107
int do_hardlink(struct sftp_conn *, const char *, const char *);
105
108
(-)a/sftp.1 (-1 / +6 lines)
Lines 137-143 will abort if any of the following Link Here
137
commands fail:
137
commands fail:
138
.Ic get , put , reget , reput, rename , ln ,
138
.Ic get , put , reget , reput, rename , ln ,
139
.Ic rm , mkdir , chdir , ls ,
139
.Ic rm , mkdir , chdir , ls ,
140
.Ic lchdir , chmod , chown ,
140
.Ic lchdir , copy , chmod , chown ,
141
.Ic chgrp , lpwd , df , symlink ,
141
.Ic chgrp , lpwd , df , symlink ,
142
and
142
and
143
.Ic lmkdir .
143
.Ic lmkdir .
Lines 340-345 may contain Link Here
340
characters and may match multiple files.
340
characters and may match multiple files.
341
.Ar own
341
.Ar own
342
must be a numeric UID.
342
must be a numeric UID.
343
.It Ic copy Ar oldpath Ar newpath
344
Copy remote file from
345
.Ar oldpath
346
to
347
.Ar newpath .
343
.It Xo Ic df
348
.It Xo Ic df
344
.Op Fl hi
349
.Op Fl hi
345
.Op Ar path
350
.Op Ar path
(-)a/sftp.c (+12 lines)
Lines 142-147 enum sftp_command { Link Here
142
	I_CHGRP,
142
	I_CHGRP,
143
	I_CHMOD,
143
	I_CHMOD,
144
	I_CHOWN,
144
	I_CHOWN,
145
	I_COPY,
145
	I_DF,
146
	I_DF,
146
	I_GET,
147
	I_GET,
147
	I_HELP,
148
	I_HELP,
Lines 185-190 static const struct CMD cmds[] = { Link Here
185
	{ "chgrp",	I_CHGRP,	REMOTE	},
186
	{ "chgrp",	I_CHGRP,	REMOTE	},
186
	{ "chmod",	I_CHMOD,	REMOTE	},
187
	{ "chmod",	I_CHMOD,	REMOTE	},
187
	{ "chown",	I_CHOWN,	REMOTE	},
188
	{ "chown",	I_CHOWN,	REMOTE	},
189
	{ "cp",		I_COPY,		REMOTE	},
188
	{ "df",		I_DF,		REMOTE	},
190
	{ "df",		I_DF,		REMOTE	},
189
	{ "dir",	I_LS,		REMOTE	},
191
	{ "dir",	I_LS,		REMOTE	},
190
	{ "exit",	I_QUIT,		NOARGS	},
192
	{ "exit",	I_QUIT,		NOARGS	},
Lines 281-286 help(void) Link Here
281
	    "chgrp grp path                     Change group of file 'path' to 'grp'\n"
283
	    "chgrp grp path                     Change group of file 'path' to 'grp'\n"
282
	    "chmod mode path                    Change permissions of file 'path' to 'mode'\n"
284
	    "chmod mode path                    Change permissions of file 'path' to 'mode'\n"
283
	    "chown own path                     Change owner of file 'path' to 'own'\n"
285
	    "chown own path                     Change owner of file 'path' to 'own'\n"
286
	    "cp oldpath newpath                 Copy remote file\n"
284
	    "df [-hi] [path]                    Display statistics for current directory or\n"
287
	    "df [-hi] [path]                    Display statistics for current directory or\n"
285
	    "                                   filesystem containing 'path'\n"
288
	    "                                   filesystem containing 'path'\n"
286
	    "exit                               Quit sftp\n"
289
	    "exit                               Quit sftp\n"
Lines 1373-1378 parse_args(const char **cpp, int *ignore_errors, int *aflag, Link Here
1373
		if ((optidx = parse_link_flags(cmd, argv, argc, sflag)) == -1)
1376
		if ((optidx = parse_link_flags(cmd, argv, argc, sflag)) == -1)
1374
			return -1;
1377
			return -1;
1375
		goto parse_two_paths;
1378
		goto parse_two_paths;
1379
	case I_COPY:
1380
		if ((optidx = parse_no_flags(cmd, argv, argc)) == -1)
1381
			return -1;
1382
		goto parse_two_paths;
1376
	case I_RENAME:
1383
	case I_RENAME:
1377
		if ((optidx = parse_rename_flags(cmd, argv, argc, lflag)) == -1)
1384
		if ((optidx = parse_rename_flags(cmd, argv, argc, lflag)) == -1)
1378
			return -1;
1385
			return -1;
Lines 1535-1540 parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, Link Here
1535
		err = process_put(conn, path1, path2, *pwd, pflag,
1542
		err = process_put(conn, path1, path2, *pwd, pflag,
1536
		    rflag, aflag, fflag);
1543
		    rflag, aflag, fflag);
1537
		break;
1544
		break;
1545
	case I_COPY:
1546
		path1 = make_absolute(path1, *pwd);
1547
		path2 = make_absolute(path2, *pwd);
1548
		err = do_copy(conn, path1, path2);
1549
		break;
1538
	case I_RENAME:
1550
	case I_RENAME:
1539
		path1 = make_absolute(path1, *pwd);
1551
		path1 = make_absolute(path1, *pwd);
1540
		path2 = make_absolute(path2, *pwd);
1552
		path2 = make_absolute(path2, *pwd);

Return to bug 2948