View | Details | Raw Unified | Return to bug 155
Collapse All | Expand All

(-)a/Makefile.inc (-1 / +1 lines)
Lines 3-9 Link Here
3
CFLAGS+=	-I${.CURDIR}/..
3
CFLAGS+=	-I${.CURDIR}/..
4
4
5
CDIAGFLAGS=	-Wall
5
CDIAGFLAGS=	-Wall
6
#CDIAGFLAGS+=	-Werror
6
CDIAGFLAGS+=	-Werror
7
CDIAGFLAGS+=	-Wpointer-arith
7
CDIAGFLAGS+=	-Wpointer-arith
8
CDIAGFLAGS+=	-Wuninitialized
8
CDIAGFLAGS+=	-Wuninitialized
9
CDIAGFLAGS+=	-Wstrict-prototypes
9
CDIAGFLAGS+=	-Wstrict-prototypes
(-)a/PROTOCOL (+16 lines)
Lines 275-278 Link Here
275
Both the "statvfs@openssh.com" and "fstatvfs@openssh.com" extensions are
275
Both the "statvfs@openssh.com" and "fstatvfs@openssh.com" extensions are
276
advertised in the SSH_FXP_VERSION hello with version "2".
276
advertised in the SSH_FXP_VERSION hello with version "2".
277
277
278
10. sftp: Extension request "hardlink@openssh.com"
279
280
This request is for creating a hard link to a regular file. This
281
request is implemented as a SSH_FXP_EXTENDED request with the
282
following format:
283
284
	uint32		id
285
	string		"hardlink@openssh.com"
286
	string		oldpath
287
	string		newpath
288
289
On receiving this request the server will perform the operation
290
link(oldpath, newpath) and will respond with a SSH_FXP_STATUS message.
291
This extension is advertised in the SSH_FXP_VERSION hello with version
292
"1".
293
278
$OpenBSD$
294
$OpenBSD$
(-)a/sftp-client.c (-1 / +39 lines)
Lines 68-73 Link Here
68
#define SFTP_EXT_POSIX_RENAME	0x00000001
68
#define SFTP_EXT_POSIX_RENAME	0x00000001
69
#define SFTP_EXT_STATVFS	0x00000002
69
#define SFTP_EXT_STATVFS	0x00000002
70
#define SFTP_EXT_FSTATVFS	0x00000004
70
#define SFTP_EXT_FSTATVFS	0x00000004
71
#define SFTP_EXT_HARDLINK	0x00000008
71
	u_int exts;
72
	u_int exts;
72
	u_int64_t limit_kbps;
73
	u_int64_t limit_kbps;
73
	struct bwlimit bwlimit_in, bwlimit_out;
74
	struct bwlimit bwlimit_in, bwlimit_out;
Lines 371-380 Link Here
371
		    strcmp(value, "2") == 0) {
372
		    strcmp(value, "2") == 0) {
372
			ret->exts |= SFTP_EXT_STATVFS;
373
			ret->exts |= SFTP_EXT_STATVFS;
373
			known = 1;
374
			known = 1;
374
		} if (strcmp(name, "fstatvfs@openssh.com") == 0 &&
375
		} else if (strcmp(name, "fstatvfs@openssh.com") == 0 &&
375
		    strcmp(value, "2") == 0) {
376
		    strcmp(value, "2") == 0) {
376
			ret->exts |= SFTP_EXT_FSTATVFS;
377
			ret->exts |= SFTP_EXT_FSTATVFS;
377
			known = 1;
378
			known = 1;
379
		} else if (strcmp(name, "hardlink@openssh.com") == 0 &&
380
		    strcmp(value, "1") == 0) {
381
			ret->exts |= SFTP_EXT_HARDLINK;
382
			known = 1;
378
		}
383
		}
379
		if (known) {
384
		if (known) {
380
			debug2("Server supports extension \"%s\" revision %s",
385
			debug2("Server supports extension \"%s\" revision %s",
Lines 788-793 Link Here
788
}
793
}
789
794
790
int
795
int
796
do_hardlink(struct sftp_conn *conn, char *oldpath, char *newpath)
797
{
798
	Buffer msg;
799
	u_int status, id;
800
801
	buffer_init(&msg);
802
803
	/* Send link request */
804
	id = conn->msg_id++;
805
	if ((conn->exts & SFTP_EXT_HARDLINK) == 0) {
806
		error("Server does not support hardlink@openssh.com extension");
807
		return -1;
808
	}
809
810
	buffer_put_char(&msg, SSH2_FXP_EXTENDED);
811
	buffer_put_int(&msg, id);
812
	buffer_put_cstring(&msg, "hardlink@openssh.com");
813
	buffer_put_cstring(&msg, oldpath);
814
	buffer_put_cstring(&msg, newpath);
815
	send_msg(conn, &msg);
816
	debug3("Sent message hardlink@openssh.com \"%s\" -> \"%s\"",
817
	       oldpath, newpath);
818
	buffer_free(&msg);
819
820
	status = get_status(conn, id);
821
	if (status != SSH2_FX_OK)
822
		error("Couldn't link file \"%s\" to \"%s\": %s", oldpath,
823
		    newpath, fx2txt(status));
824
825
	return(status);
826
}
827
828
int
791
do_symlink(struct sftp_conn *conn, char *oldpath, char *newpath)
829
do_symlink(struct sftp_conn *conn, char *oldpath, char *newpath)
792
{
830
{
793
	Buffer msg;
831
	Buffer msg;
(-)a/sftp-client.h (+3 lines)
Lines 94-99 Link Here
94
/* Rename 'oldpath' to 'newpath' */
94
/* Rename 'oldpath' to 'newpath' */
95
int do_rename(struct sftp_conn *, char *, char *);
95
int do_rename(struct sftp_conn *, char *, char *);
96
96
97
/* Link 'oldpath' to 'newpath' */
98
int do_hardlink(struct sftp_conn *, char *, char *);
99
97
/* Rename 'oldpath' to 'newpath' */
100
/* Rename 'oldpath' to 'newpath' */
98
int do_symlink(struct sftp_conn *, char *, char *);
101
int do_symlink(struct sftp_conn *, char *, char *);
99
102
(-)a/sftp-server.c (+26 lines)
Lines 526-531 Link Here
526
	/* fstatvfs extension */
526
	/* fstatvfs extension */
527
	buffer_put_cstring(&msg, "fstatvfs@openssh.com");
527
	buffer_put_cstring(&msg, "fstatvfs@openssh.com");
528
	buffer_put_cstring(&msg, "2"); /* version */
528
	buffer_put_cstring(&msg, "2"); /* version */
529
	/* hardlink extension */
530
	buffer_put_cstring(&msg, "hardlink@openssh.com");
531
	buffer_put_cstring(&msg, "1"); /* version */
529
	send_msg(&msg);
532
	send_msg(&msg);
530
	buffer_free(&msg);
533
	buffer_free(&msg);
531
}
534
}
Lines 1195-1200 Link Here
1195
}
1198
}
1196
1199
1197
static void
1200
static void
1201
process_extended_hardlink(u_int32_t id)
1202
{
1203
	char *oldpath, *newpath;
1204
	int ret, status;
1205
1206
	oldpath = get_string(NULL);
1207
	newpath = get_string(NULL);
1208
	debug3("request %u: hardlink", id);
1209
	logit("hardlink old \"%s\" new \"%s\"", oldpath, newpath);
1210
	if (readonly)
1211
		status = SSH2_FX_PERMISSION_DENIED;
1212
	else {
1213
		ret = link(oldpath, newpath);
1214
		status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
1215
	}
1216
	send_status(id, status);
1217
	xfree(oldpath);
1218
	xfree(newpath);
1219
}
1220
1221
static void
1198
process_extended(void)
1222
process_extended(void)
1199
{
1223
{
1200
	u_int32_t id;
1224
	u_int32_t id;
Lines 1208-1213 Link Here
1208
		process_extended_statvfs(id);
1232
		process_extended_statvfs(id);
1209
	else if (strcmp(request, "fstatvfs@openssh.com") == 0)
1233
	else if (strcmp(request, "fstatvfs@openssh.com") == 0)
1210
		process_extended_fstatvfs(id);
1234
		process_extended_fstatvfs(id);
1235
	else if (strcmp(request, "hardlink@openssh.com") == 0)
1236
		process_extended_hardlink(id);
1211
	else
1237
	else
1212
		send_status(id, SSH2_FX_OP_UNSUPPORTED);	/* MUST */
1238
		send_status(id, SSH2_FX_OP_UNSUPPORTED);	/* MUST */
1213
	xfree(request);
1239
	xfree(request);
(-)a/sftp.1 (-3 / +11 lines)
Lines 128-134 Link Here
128
.Ic get , put , rename , ln ,
128
.Ic get , put , rename , ln ,
129
.Ic rm , mkdir , chdir , ls ,
129
.Ic rm , mkdir , chdir , ls ,
130
.Ic lchdir , chmod , chown ,
130
.Ic lchdir , chmod , chown ,
131
.Ic chgrp , lpwd , df ,
131
.Ic chgrp , lpwd , df , symlink ,
132
and
132
and
133
.Ic lmkdir .
133
.Ic lmkdir .
134
Termination on error can be suppressed on a command by command basis by
134
Termination on error can be suppressed on a command by command basis by
Lines 392-402 Link Here
392
.It Ic lmkdir Ar path
392
.It Ic lmkdir Ar path
393
Create local directory specified by
393
Create local directory specified by
394
.Ar path .
394
.Ar path .
395
.It Ic ln Ar oldpath Ar newpath
395
.It Xo Ic ln
396
Create a symbolic link from
396
.Op Fl s
397
.Ar oldpath
398
.Ar newpath
399
.Xc
400
Create a link from
397
.Ar oldpath
401
.Ar oldpath
398
to
402
to
399
.Ar newpath .
403
.Ar newpath .
404
If the
405
.Fl s
406
flag is specified the created link is a symbolic link, otherwise it is
407
a hard link.
400
.It Ic lpwd
408
.It Ic lpwd
401
Print local working directory.
409
Print local working directory.
402
.It Xo Ic ls
410
.It Xo Ic ls
(-)a/sftp.c (-9 / +42 lines)
Lines 109-114 Link Here
109
#define I_GET		5
109
#define I_GET		5
110
#define I_HELP		6
110
#define I_HELP		6
111
#define I_LCHDIR	7
111
#define I_LCHDIR	7
112
#define I_LINK		25
112
#define I_LLS		8
113
#define I_LLS		8
113
#define I_LMKDIR	9
114
#define I_LMKDIR	9
114
#define I_LPWD		10
115
#define I_LPWD		10
Lines 153-159 Link Here
153
	{ "lchdir",	I_LCHDIR,	LOCAL	},
154
	{ "lchdir",	I_LCHDIR,	LOCAL	},
154
	{ "lls",	I_LLS,		LOCAL	},
155
	{ "lls",	I_LLS,		LOCAL	},
155
	{ "lmkdir",	I_LMKDIR,	LOCAL	},
156
	{ "lmkdir",	I_LMKDIR,	LOCAL	},
156
	{ "ln",		I_SYMLINK,	REMOTE	},
157
	{ "ln",		I_LINK,		REMOTE	},
157
	{ "lpwd",	I_LPWD,		LOCAL	},
158
	{ "lpwd",	I_LPWD,		LOCAL	},
158
	{ "ls",		I_LS,		REMOTE	},
159
	{ "ls",		I_LS,		REMOTE	},
159
	{ "lumask",	I_LUMASK,	NOARGS	},
160
	{ "lumask",	I_LUMASK,	NOARGS	},
Lines 217-223 Link Here
217
	    "lcd path                           Change local directory to 'path'\n"
218
	    "lcd path                           Change local directory to 'path'\n"
218
	    "lls [ls-options [path]]            Display local directory listing\n"
219
	    "lls [ls-options [path]]            Display local directory listing\n"
219
	    "lmkdir path                        Create local directory\n"
220
	    "lmkdir path                        Create local directory\n"
220
	    "ln oldpath newpath                 Symlink remote file\n"
221
	    "ln [-s] oldpath newpath            Link remote file (-s for symlink)\n"
221
	    "lpwd                               Print local working directory\n"
222
	    "lpwd                               Print local working directory\n"
222
	    "ls [-1afhlnrSt] [path]             Display remote directory listing\n"
223
	    "ls [-1afhlnrSt] [path]             Display remote directory listing\n"
223
	    "lumask umask                       Set local umask to 'umask'\n"
224
	    "lumask umask                       Set local umask to 'umask'\n"
Lines 354-359 Link Here
354
}
355
}
355
356
356
static int
357
static int
358
parse_link_flags(const char *cmd, char **argv, int argc, int *sflag)
359
{
360
	extern int opterr, optind, optopt, optreset;
361
	int ch;
362
363
	optind = optreset = 1;
364
	opterr = 0;
365
366
	*sflag = 0;
367
	while ((ch = getopt(argc, argv, "s")) != -1) {
368
		switch (ch) {
369
		case 's':
370
			*sflag = 1;
371
			break;
372
		default:
373
			error("%s: Invalid flag -%c", cmd, optopt);
374
			return -1;
375
		}
376
	}
377
378
	return optind;
379
}
380
381
static int
357
parse_ls_flags(char **argv, int argc, int *lflag)
382
parse_ls_flags(char **argv, int argc, int *lflag)
358
{
383
{
359
	extern int opterr, optind, optopt, optreset;
384
	extern int opterr, optind, optopt, optreset;
Lines 1065-1071 Link Here
1065
1090
1066
static int
1091
static int
1067
parse_args(const char **cpp, int *pflag, int *rflag, int *lflag, int *iflag,
1092
parse_args(const char **cpp, int *pflag, int *rflag, int *lflag, int *iflag,
1068
    int *hflag, unsigned long *n_arg, char **path1, char **path2)
1093
    int *hflag, int *sflag, unsigned long *n_arg, char **path1, char **path2)
1069
{
1094
{
1070
	const char *cmd, *cp = *cpp;
1095
	const char *cmd, *cp = *cpp;
1071
	char *cp2, **argv;
1096
	char *cp2, **argv;
Lines 1115-1121 Link Here
1115
	switch (cmdnum) {
1140
	switch (cmdnum) {
1116
	case I_GET:
1141
	case I_GET:
1117
	case I_PUT:
1142
	case I_PUT:
1118
		if ((optidx = parse_getput_flags(cmd, argv, argc, pflag, rflag)) == -1)
1143
		if ((optidx = parse_getput_flags(cmd, argv, argc,
1144
		    pflag, rflag)) == -1)
1119
			return -1;
1145
			return -1;
1120
		/* Get first pathname (mandatory) */
1146
		/* Get first pathname (mandatory) */
1121
		if (argc - optidx < 1) {
1147
		if (argc - optidx < 1) {
Lines 1131-1138 Link Here
1131
			undo_glob_escape(*path2);
1157
			undo_glob_escape(*path2);
1132
		}
1158
		}
1133
		break;
1159
		break;
1160
	case I_LINK:
1161
		if ((optidx = parse_link_flags(cmd, argv, argc, sflag)) == -1)
1162
			return -1;
1163
	case I_SYMLINK:
1134
	case I_RENAME:
1164
	case I_RENAME:
1135
	case I_SYMLINK:
1136
		if (argc - optidx < 2) {
1165
		if (argc - optidx < 2) {
1137
			error("You must specify two paths after a %s "
1166
			error("You must specify two paths after a %s "
1138
			    "command.", cmd);
1167
			    "command.", cmd);
Lines 1235-1241 Link Here
1235
    int err_abort)
1264
    int err_abort)
1236
{
1265
{
1237
	char *path1, *path2, *tmp;
1266
	char *path1, *path2, *tmp;
1238
	int pflag = 0, rflag = 0, lflag = 0, iflag = 0, hflag = 0, cmdnum, i;
1267
	int pflag = 0, rflag = 0, lflag = 0, iflag = 0, hflag = 0, sflag = 0;
1268
	int cmdnum, i;
1239
	unsigned long n_arg = 0;
1269
	unsigned long n_arg = 0;
1240
	Attrib a, *aa;
1270
	Attrib a, *aa;
1241
	char path_buf[MAXPATHLEN];
1271
	char path_buf[MAXPATHLEN];
Lines 1243-1250 Link Here
1243
	glob_t g;
1273
	glob_t g;
1244
1274
1245
	path1 = path2 = NULL;
1275
	path1 = path2 = NULL;
1246
	cmdnum = parse_args(&cmd, &pflag, &rflag, &lflag, &iflag, &hflag, &n_arg,
1276
	cmdnum = parse_args(&cmd, &pflag, &rflag, &lflag, &iflag, &hflag,
1247
	    &path1, &path2);
1277
	    &sflag, &n_arg, &path1, &path2);
1248
1278
1249
	if (iflag != 0)
1279
	if (iflag != 0)
1250
		err_abort = 0;
1280
		err_abort = 0;
Lines 1272-1279 Link Here
1272
		err = do_rename(conn, path1, path2);
1302
		err = do_rename(conn, path1, path2);
1273
		break;
1303
		break;
1274
	case I_SYMLINK:
1304
	case I_SYMLINK:
1305
		sflag = 1;
1306
	case I_LINK:
1307
		path1 = make_absolute(path1, *pwd);
1275
		path2 = make_absolute(path2, *pwd);
1308
		path2 = make_absolute(path2, *pwd);
1276
		err = do_symlink(conn, path1, path2);
1309
		err = (sflag ? do_symlink : do_hardlink)(conn, path1, path2);
1277
		break;
1310
		break;
1278
	case I_RM:
1311
	case I_RM:
1279
		path1 = make_absolute(path1, *pwd);
1312
		path1 = make_absolute(path1, *pwd);

Return to bug 155