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

Collapse All | Expand All

(-)a/sftp-client.c (-3 / +37 lines)
Lines 72-77 struct sftp_conn { Link Here
72
#define SFTP_EXT_FSTATVFS	0x00000004
72
#define SFTP_EXT_FSTATVFS	0x00000004
73
#define SFTP_EXT_HARDLINK	0x00000008
73
#define SFTP_EXT_HARDLINK	0x00000008
74
#define SFTP_EXT_FSYNC		0x00000010
74
#define SFTP_EXT_FSYNC		0x00000010
75
#define SFTP_EXT_LSETSTAT	0x00000020
75
	u_int exts;
76
	u_int exts;
76
	u_int64_t limit_kbps;
77
	u_int64_t limit_kbps;
77
	struct bwlimit bwlimit_in, bwlimit_out;
78
	struct bwlimit bwlimit_in, bwlimit_out;
Lines 449-454 do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests, Link Here
449
		    strcmp((char *)value, "1") == 0) {
450
		    strcmp((char *)value, "1") == 0) {
450
			ret->exts |= SFTP_EXT_FSYNC;
451
			ret->exts |= SFTP_EXT_FSYNC;
451
			known = 1;
452
			known = 1;
453
		} else if (strcmp(name, "lsetstat@openssh.com") == 0 &&
454
		    strcmp((char *)value, "1") == 0) {
455
			ret->exts |= SFTP_EXT_LSETSTAT;
456
			known = 1;
452
		}
457
		}
453
		if (known) {
458
		if (known) {
454
			debug2("Server supports extension \"%s\" revision %s",
459
			debug2("Server supports extension \"%s\" revision %s",
Lines 1082-1088 do_statvfs(struct sftp_conn *conn, const char *path, struct sftp_statvfs *st, Link Here
1082
1087
1083
	if ((msg = sshbuf_new()) == NULL)
1088
	if ((msg = sshbuf_new()) == NULL)
1084
		fatal("%s: sshbuf_new failed", __func__);
1089
		fatal("%s: sshbuf_new failed", __func__);
1085
	sshbuf_reset(msg);
1086
	if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
1090
	if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
1087
	    (r = sshbuf_put_u32(msg, id)) != 0 ||
1091
	    (r = sshbuf_put_u32(msg, id)) != 0 ||
1088
	    (r = sshbuf_put_cstring(msg, "statvfs@openssh.com")) != 0 ||
1092
	    (r = sshbuf_put_cstring(msg, "statvfs@openssh.com")) != 0 ||
Lines 1111-1117 do_fstatvfs(struct sftp_conn *conn, const u_char *handle, u_int handle_len, Link Here
1111
1115
1112
	if ((msg = sshbuf_new()) == NULL)
1116
	if ((msg = sshbuf_new()) == NULL)
1113
		fatal("%s: sshbuf_new failed", __func__);
1117
		fatal("%s: sshbuf_new failed", __func__);
1114
	sshbuf_reset(msg);
1115
	if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
1118
	if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
1116
	    (r = sshbuf_put_u32(msg, id)) != 0 ||
1119
	    (r = sshbuf_put_u32(msg, id)) != 0 ||
1117
	    (r = sshbuf_put_cstring(msg, "fstatvfs@openssh.com")) != 0 ||
1120
	    (r = sshbuf_put_cstring(msg, "fstatvfs@openssh.com")) != 0 ||
Lines 1124-1129 do_fstatvfs(struct sftp_conn *conn, const u_char *handle, u_int handle_len, Link Here
1124
}
1127
}
1125
#endif
1128
#endif
1126
1129
1130
int
1131
do_lsetstat(struct sftp_conn *conn, const char *path, Attrib *a)
1132
{
1133
	struct sshbuf *msg;
1134
	u_int status, id;
1135
	int r;
1136
1137
	if ((conn->exts & SFTP_EXT_LSETSTAT) == 0) {
1138
		error("Server does not support lsetstat@openssh.com extension");
1139
		return -1;
1140
	}
1141
1142
	id = conn->msg_id++;
1143
	if ((msg = sshbuf_new()) == NULL)
1144
		fatal("%s: sshbuf_new failed", __func__);
1145
	if ((r = sshbuf_put_u8(msg, SSH2_FXP_EXTENDED)) != 0 ||
1146
	    (r = sshbuf_put_u32(msg, id)) != 0 ||
1147
	    (r = sshbuf_put_cstring(msg, "lsetstat@openssh.com")) != 0 ||
1148
	    (r = sshbuf_put_cstring(msg, path)) != 0 ||
1149
	    (r = encode_attrib(msg, a)) != 0)
1150
		fatal("%s: buffer error: %s", __func__, ssh_err(r));
1151
	send_msg(conn, msg);
1152
	sshbuf_free(msg);
1153
1154
	status = get_status(conn, id);
1155
	if (status != SSH2_FX_OK)
1156
		error("Couldn't setstat on \"%s\": %s", path,
1157
		    fx2txt(status));
1158
1159
	return status == SSH2_FX_OK ? 0 : -1;
1160
}
1161
1127
static void
1162
static void
1128
send_read_request(struct sftp_conn *conn, u_int id, u_int64_t offset,
1163
send_read_request(struct sftp_conn *conn, u_int id, u_int64_t offset,
1129
    u_int len, const u_char *handle, u_int handle_len)
1164
    u_int len, const u_char *handle, u_int handle_len)
Lines 1133-1139 send_read_request(struct sftp_conn *conn, u_int id, u_int64_t offset, Link Here
1133
1168
1134
	if ((msg = sshbuf_new()) == NULL)
1169
	if ((msg = sshbuf_new()) == NULL)
1135
		fatal("%s: sshbuf_new failed", __func__);
1170
		fatal("%s: sshbuf_new failed", __func__);
1136
	sshbuf_reset(msg);
1137
	if ((r = sshbuf_put_u8(msg, SSH2_FXP_READ)) != 0 ||
1171
	if ((r = sshbuf_put_u8(msg, SSH2_FXP_READ)) != 0 ||
1138
	    (r = sshbuf_put_u32(msg, id)) != 0 ||
1172
	    (r = sshbuf_put_u32(msg, id)) != 0 ||
1139
	    (r = sshbuf_put_string(msg, handle, handle_len)) != 0 ||
1173
	    (r = sshbuf_put_string(msg, handle, handle_len)) != 0 ||
(-)a/sftp-client.h (+3 lines)
Lines 85-90 int do_setstat(struct sftp_conn *, const char *, Attrib *); Link Here
85
/* Set file attributes of open file 'handle' */
85
/* Set file attributes of open file 'handle' */
86
int do_fsetstat(struct sftp_conn *, const u_char *, u_int, Attrib *);
86
int do_fsetstat(struct sftp_conn *, const u_char *, u_int, Attrib *);
87
87
88
/* Set file attributes of 'path', not following symlinks */
89
int do_lsetstat(struct sftp_conn *conn, const char *path, Attrib *a);
90
88
/* Canonicalise 'path' - caller must free result */
91
/* Canonicalise 'path' - caller must free result */
89
char *do_realpath(struct sftp_conn *, const char *);
92
char *do_realpath(struct sftp_conn *, const char *);
90
93
(-)a/sftp-server.c (+65 lines)
Lines 99-104 static void process_extended_statvfs(u_int32_t id); Link Here
99
static void process_extended_fstatvfs(u_int32_t id);
99
static void process_extended_fstatvfs(u_int32_t id);
100
static void process_extended_hardlink(u_int32_t id);
100
static void process_extended_hardlink(u_int32_t id);
101
static void process_extended_fsync(u_int32_t id);
101
static void process_extended_fsync(u_int32_t id);
102
static void process_extended_lsetstat(u_int32_t id);
102
static void process_extended(u_int32_t id);
103
static void process_extended(u_int32_t id);
103
104
104
struct sftp_handler {
105
struct sftp_handler {
Lines 140-145 static const struct sftp_handler extended_handlers[] = { Link Here
140
	{ "fstatvfs", "fstatvfs@openssh.com", 0, process_extended_fstatvfs, 0 },
141
	{ "fstatvfs", "fstatvfs@openssh.com", 0, process_extended_fstatvfs, 0 },
141
	{ "hardlink", "hardlink@openssh.com", 0, process_extended_hardlink, 1 },
142
	{ "hardlink", "hardlink@openssh.com", 0, process_extended_hardlink, 1 },
142
	{ "fsync", "fsync@openssh.com", 0, process_extended_fsync, 1 },
143
	{ "fsync", "fsync@openssh.com", 0, process_extended_fsync, 1 },
144
	{ "lsetstat", "lsetstat@openssh.com", 0, process_extended_lsetstat, 1 },
143
	{ NULL, NULL, 0, NULL, 0 }
145
	{ NULL, NULL, 0, NULL, 0 }
144
};
146
};
145
147
Lines 658-663 process_init(void) Link Here
658
	    (r = sshbuf_put_cstring(msg, "1")) != 0 || /* version */
660
	    (r = sshbuf_put_cstring(msg, "1")) != 0 || /* version */
659
	    /* fsync extension */
661
	    /* fsync extension */
660
	    (r = sshbuf_put_cstring(msg, "fsync@openssh.com")) != 0 ||
662
	    (r = sshbuf_put_cstring(msg, "fsync@openssh.com")) != 0 ||
663
	    (r = sshbuf_put_cstring(msg, "1")) != 0 || /* version */
664
	    (r = sshbuf_put_cstring(msg, "lsetstat@openssh.com")) != 0 ||
661
	    (r = sshbuf_put_cstring(msg, "1")) != 0) /* version */
665
	    (r = sshbuf_put_cstring(msg, "1")) != 0) /* version */
662
		fatal("%s: buffer error: %s", __func__, ssh_err(r));
666
		fatal("%s: buffer error: %s", __func__, ssh_err(r));
663
	send_msg(msg);
667
	send_msg(msg);
Lines 881-886 attrib_to_tv(const Attrib *a) Link Here
881
	return tv;
885
	return tv;
882
}
886
}
883
887
888
static struct timespec *
889
attrib_to_ts(const Attrib *a)
890
{
891
	static struct timespec ts[2];
892
893
	ts[0].tv_sec = a->atime;
894
	ts[0].tv_nsec = 0;
895
	ts[1].tv_sec = a->mtime;
896
	ts[1].tv_nsec = 0;
897
	return ts;
898
}
899
884
static void
900
static void
885
process_setstat(u_int32_t id)
901
process_setstat(u_int32_t id)
886
{
902
{
Lines 1342-1347 process_extended_fsync(u_int32_t id) Link Here
1342
	send_status(id, status);
1358
	send_status(id, status);
1343
}
1359
}
1344
1360
1361
static void
1362
process_extended_lsetstat(u_int32_t id)
1363
{
1364
	Attrib a;
1365
	char *name;
1366
	int r, status = SSH2_FX_OK;
1367
1368
	if ((r = sshbuf_get_cstring(iqueue, &name, NULL)) != 0 ||
1369
	    (r = decode_attrib(iqueue, &a)) != 0)
1370
		fatal("%s: buffer error: %s", __func__, ssh_err(r));
1371
1372
	debug("request %u: lsetstat name \"%s\"", id, name);
1373
	if (a.flags & SSH2_FILEXFER_ATTR_SIZE) {
1374
		/* nonsensical for links */
1375
		status = SSH2_FX_BAD_MESSAGE;
1376
		goto out;
1377
	}
1378
	if (a.flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
1379
		logit("set \"%s\" mode %04o", name, a.perm);
1380
		r = fchmodat(AT_FDCWD, name,
1381
		    a.perm & 07777, AT_SYMLINK_NOFOLLOW);
1382
		if (r == -1)
1383
			status = errno_to_portable(errno);
1384
	}
1385
	if (a.flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
1386
		char buf[64];
1387
		time_t t = a.mtime;
1388
1389
		strftime(buf, sizeof(buf), "%Y%m%d-%H:%M:%S",
1390
		    localtime(&t));
1391
		logit("set \"%s\" modtime %s", name, buf);
1392
		r = utimensat(AT_FDCWD, name,
1393
		    attrib_to_ts(&a), AT_SYMLINK_NOFOLLOW);
1394
		if (r == -1)
1395
			status = errno_to_portable(errno);
1396
	}
1397
	if (a.flags & SSH2_FILEXFER_ATTR_UIDGID) {
1398
		logit("set \"%s\" owner %lu group %lu", name,
1399
		    (u_long)a.uid, (u_long)a.gid);
1400
		r = fchownat(AT_FDCWD, name, a.uid, a.gid,
1401
		    AT_SYMLINK_NOFOLLOW);
1402
		if (r == -1)
1403
			status = errno_to_portable(errno);
1404
	}
1405
 out:
1406
	send_status(id, status);
1407
	free(name);
1408
}
1409
1345
static void
1410
static void
1346
process_extended(u_int32_t id)
1411
process_extended(u_int32_t id)
1347
{
1412
{
(-)a/sftp.1 (-3 / +24 lines)
Lines 316-346 Change remote directory to Link Here
316
If
316
If
317
.Ar path
317
.Ar path
318
is not specified, then change directory to the one the session started in.
318
is not specified, then change directory to the one the session started in.
319
.It Ic chgrp Ar grp Ar path
319
.It Xo Ic chgrp
320
.Op Fl h
321
.Ar grp
322
.Ar path
323
.Xc
320
Change group of file
324
Change group of file
321
.Ar path
325
.Ar path
322
to
326
to
323
.Ar grp .
327
.Ar grp .
328
If the
329
.Fl h
330
flag is specified, then symlinks will not be followed.
324
.Ar path
331
.Ar path
325
may contain
332
may contain
326
.Xr glob 7
333
.Xr glob 7
327
characters and may match multiple files.
334
characters and may match multiple files.
328
.Ar grp
335
.Ar grp
329
must be a numeric GID.
336
must be a numeric GID.
330
.It Ic chmod Ar mode Ar path
337
.It Xo Ic chmod
338
.Op Fl h
339
.Ar mode
340
.Ar path
341
.Xc
331
Change permissions of file
342
Change permissions of file
332
.Ar path
343
.Ar path
333
to
344
to
334
.Ar mode .
345
.Ar mode .
346
If the
347
.Fl h
348
flag is specified, then symlinks will not be followed.
335
.Ar path
349
.Ar path
336
may contain
350
may contain
337
.Xr glob 7
351
.Xr glob 7
338
characters and may match multiple files.
352
characters and may match multiple files.
339
.It Ic chown Ar own Ar path
353
.It Xo Ic chown
354
.Op Fl h
355
.Ar own
356
.Ar path
357
.Xc
340
Change owner of file
358
Change owner of file
341
.Ar path
359
.Ar path
342
to
360
to
343
.Ar own .
361
.Ar own .
362
If the
363
.Fl h
364
flag is specified, then symlinks will not be followed.
344
.Ar path
365
.Ar path
345
may contain
366
may contain
346
.Xr glob 7
367
.Xr glob 7
(-)a/sftp.c (-7 / +34 lines)
Lines 256-264 help(void) Link Here
256
	printf("Available commands:\n"
256
	printf("Available commands:\n"
257
	    "bye                                Quit sftp\n"
257
	    "bye                                Quit sftp\n"
258
	    "cd path                            Change remote directory to 'path'\n"
258
	    "cd path                            Change remote directory to 'path'\n"
259
	    "chgrp grp path                     Change group of file 'path' to 'grp'\n"
259
	    "chgrp [-h] grp path                Change group of file 'path' to 'grp'\n"
260
	    "chmod mode path                    Change permissions of file 'path' to 'mode'\n"
260
	    "chmod [-h] mode path               Change permissions of file 'path' to 'mode'\n"
261
	    "chown own path                     Change owner of file 'path' to 'own'\n"
261
	    "chown [-h] own path                Change owner of file 'path' to 'own'\n"
262
	    "df [-hi] [path]                    Display statistics for current directory or\n"
262
	    "df [-hi] [path]                    Display statistics for current directory or\n"
263
	    "                                   filesystem containing 'path'\n"
263
	    "                                   filesystem containing 'path'\n"
264
	    "exit                               Quit sftp\n"
264
	    "exit                               Quit sftp\n"
Lines 539-544 parse_df_flags(const char *cmd, char **argv, int argc, int *hflag, int *iflag) Link Here
539
	return optind;
539
	return optind;
540
}
540
}
541
541
542
static int
543
parse_ch_flags(const char *cmd, char **argv, int argc, int *hflag)
544
{
545
	extern int opterr, optind, optopt, optreset;
546
	int ch;
547
548
	optind = optreset = 1;
549
	opterr = 0;
550
551
	*hflag = 0;
552
	while ((ch = getopt(argc, argv, "h")) != -1) {
553
		switch (ch) {
554
		case 'h':
555
			*hflag = 1;
556
			break;
557
		default:
558
			error("%s: Invalid flag -%c", cmd, optopt);
559
			return -1;
560
		}
561
	}
562
563
	return optind;
564
}
565
542
static int
566
static int
543
parse_no_flags(const char *cmd, char **argv, int argc)
567
parse_no_flags(const char *cmd, char **argv, int argc)
544
{
568
{
Lines 1428-1434 parse_args(const char **cpp, int *ignore_errors, int *disable_echo, int *aflag, Link Here
1428
		/* FALLTHROUGH */
1452
		/* FALLTHROUGH */
1429
	case I_CHOWN:
1453
	case I_CHOWN:
1430
	case I_CHGRP:
1454
	case I_CHGRP:
1431
		if ((optidx = parse_no_flags(cmd, argv, argc)) == -1)
1455
		if ((optidx = parse_ch_flags(cmd, argv, argc, hflag)) == -1)
1432
			return -1;
1456
			return -1;
1433
		/* Get numeric arg (mandatory) */
1457
		/* Get numeric arg (mandatory) */
1434
		if (argc - optidx < 1)
1458
		if (argc - optidx < 1)
Lines 1647-1653 parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, Link Here
1647
			if (!quiet)
1671
			if (!quiet)
1648
				mprintf("Changing mode on %s\n",
1672
				mprintf("Changing mode on %s\n",
1649
				    g.gl_pathv[i]);
1673
				    g.gl_pathv[i]);
1650
			err = do_setstat(conn, g.gl_pathv[i], &a);
1674
			err = (hflag ? do_lsetstat : do_setstat)(conn,
1675
			    g.gl_pathv[i], &a);
1651
			if (err != 0 && err_abort)
1676
			if (err != 0 && err_abort)
1652
				break;
1677
				break;
1653
		}
1678
		}
Lines 1657-1663 parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, Link Here
1657
		path1 = make_absolute(path1, *pwd);
1682
		path1 = make_absolute(path1, *pwd);
1658
		remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
1683
		remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
1659
		for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
1684
		for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
1660
			if (!(aa = do_stat(conn, g.gl_pathv[i], 0))) {
1685
			if (!(aa = (hflag ? do_lstat : do_stat)(conn,
1686
			    g.gl_pathv[i], 0))) {
1661
				if (err_abort) {
1687
				if (err_abort) {
1662
					err = -1;
1688
					err = -1;
1663
					break;
1689
					break;
Lines 1685-1691 parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, Link Here
1685
					    g.gl_pathv[i]);
1711
					    g.gl_pathv[i]);
1686
				aa->gid = n_arg;
1712
				aa->gid = n_arg;
1687
			}
1713
			}
1688
			err = do_setstat(conn, g.gl_pathv[i], aa);
1714
			err = (hflag ? do_lsetstat : do_setstat)(conn,
1715
			    g.gl_pathv[i], aa);
1689
			if (err != 0 && err_abort)
1716
			if (err != 0 && err_abort)
1690
				break;
1717
				break;
1691
		}
1718
		}

Return to bug 2067