mirror of git://anongit.mindrot.org/openssh.git
- djm@cvs.openbsd.org 2010/12/04 00:18:01
[sftp-server.c sftp.1 sftp-client.h sftp.c PROTOCOL sftp-client.c] add a protocol extension to support a hard link operation. It is available through the "ln" command in the client. The old "ln" behaviour of creating a symlink is available using its "-s" option or through the preexisting "symlink" command; based on a patch from miklos AT szeredi.hu in bz#1555; ok markus@
This commit is contained in:
parent
adab6f1299
commit
af1f909254
|
@ -11,6 +11,13 @@
|
|||
[auth-rsa.c]
|
||||
move check for revoked keys to run earlier (in auth_rsa_key_allowed)
|
||||
bz#1829; patch from ldv AT altlinux.org; ok markus@
|
||||
- djm@cvs.openbsd.org 2010/12/04 00:18:01
|
||||
[sftp-server.c sftp.1 sftp-client.h sftp.c PROTOCOL sftp-client.c]
|
||||
add a protocol extension to support a hard link operation. It is
|
||||
available through the "ln" command in the client. The old "ln"
|
||||
behaviour of creating a symlink is available using its "-s" option
|
||||
or through the preexisting "symlink" command; based on a patch from
|
||||
miklos AT szeredi.hu in bz#1555; ok markus@
|
||||
|
||||
20101204
|
||||
- (djm) [openbsd-compat/bindresvport.c] Use arc4random_uniform(range)
|
||||
|
|
18
PROTOCOL
18
PROTOCOL
|
@ -275,4 +275,20 @@ The values of the f_flag bitmask are as follows:
|
|||
Both the "statvfs@openssh.com" and "fstatvfs@openssh.com" extensions are
|
||||
advertised in the SSH_FXP_VERSION hello with version "2".
|
||||
|
||||
$OpenBSD: PROTOCOL,v 1.16 2010/08/31 11:54:45 djm Exp $
|
||||
10. sftp: Extension request "hardlink@openssh.com"
|
||||
|
||||
This request is for creating a hard link to a regular file. This
|
||||
request is implemented as a SSH_FXP_EXTENDED request with the
|
||||
following format:
|
||||
|
||||
uint32 id
|
||||
string "hardlink@openssh.com"
|
||||
string oldpath
|
||||
string newpath
|
||||
|
||||
On receiving this request the server will perform the operation
|
||||
link(oldpath, newpath) and will respond with a SSH_FXP_STATUS message.
|
||||
This extension is advertised in the SSH_FXP_VERSION hello with version
|
||||
"1".
|
||||
|
||||
$OpenBSD: PROTOCOL,v 1.17 2010/12/04 00:18:01 djm Exp $
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: sftp-client.c,v 1.93 2010/09/22 22:58:51 djm Exp $ */
|
||||
/* $OpenBSD: sftp-client.c,v 1.94 2010/12/04 00:18:01 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
|
||||
*
|
||||
|
@ -75,6 +75,7 @@ struct sftp_conn {
|
|||
#define SFTP_EXT_POSIX_RENAME 0x00000001
|
||||
#define SFTP_EXT_STATVFS 0x00000002
|
||||
#define SFTP_EXT_FSTATVFS 0x00000004
|
||||
#define SFTP_EXT_HARDLINK 0x00000008
|
||||
u_int exts;
|
||||
u_int64_t limit_kbps;
|
||||
struct bwlimit bwlimit_in, bwlimit_out;
|
||||
|
@ -378,10 +379,14 @@ do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests,
|
|||
strcmp(value, "2") == 0) {
|
||||
ret->exts |= SFTP_EXT_STATVFS;
|
||||
known = 1;
|
||||
} if (strcmp(name, "fstatvfs@openssh.com") == 0 &&
|
||||
} else if (strcmp(name, "fstatvfs@openssh.com") == 0 &&
|
||||
strcmp(value, "2") == 0) {
|
||||
ret->exts |= SFTP_EXT_FSTATVFS;
|
||||
known = 1;
|
||||
} else if (strcmp(name, "hardlink@openssh.com") == 0 &&
|
||||
strcmp(value, "1") == 0) {
|
||||
ret->exts |= SFTP_EXT_HARDLINK;
|
||||
known = 1;
|
||||
}
|
||||
if (known) {
|
||||
debug2("Server supports extension \"%s\" revision %s",
|
||||
|
@ -794,6 +799,39 @@ do_rename(struct sftp_conn *conn, char *oldpath, char *newpath)
|
|||
return(status);
|
||||
}
|
||||
|
||||
int
|
||||
do_hardlink(struct sftp_conn *conn, char *oldpath, char *newpath)
|
||||
{
|
||||
Buffer msg;
|
||||
u_int status, id;
|
||||
|
||||
buffer_init(&msg);
|
||||
|
||||
/* Send link request */
|
||||
id = conn->msg_id++;
|
||||
if ((conn->exts & SFTP_EXT_HARDLINK) == 0) {
|
||||
error("Server does not support hardlink@openssh.com extension");
|
||||
return -1;
|
||||
}
|
||||
|
||||
buffer_put_char(&msg, SSH2_FXP_EXTENDED);
|
||||
buffer_put_int(&msg, id);
|
||||
buffer_put_cstring(&msg, "hardlink@openssh.com");
|
||||
buffer_put_cstring(&msg, oldpath);
|
||||
buffer_put_cstring(&msg, newpath);
|
||||
send_msg(conn, &msg);
|
||||
debug3("Sent message hardlink@openssh.com \"%s\" -> \"%s\"",
|
||||
oldpath, newpath);
|
||||
buffer_free(&msg);
|
||||
|
||||
status = get_status(conn, id);
|
||||
if (status != SSH2_FX_OK)
|
||||
error("Couldn't link file \"%s\" to \"%s\": %s", oldpath,
|
||||
newpath, fx2txt(status));
|
||||
|
||||
return(status);
|
||||
}
|
||||
|
||||
int
|
||||
do_symlink(struct sftp_conn *conn, char *oldpath, char *newpath)
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: sftp-client.h,v 1.19 2010/09/22 22:58:51 djm Exp $ */
|
||||
/* $OpenBSD: sftp-client.h,v 1.20 2010/12/04 00:18:01 djm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
|
||||
|
@ -94,6 +94,9 @@ int do_statvfs(struct sftp_conn *, const char *, struct sftp_statvfs *, int);
|
|||
/* Rename 'oldpath' to 'newpath' */
|
||||
int do_rename(struct sftp_conn *, char *, char *);
|
||||
|
||||
/* Link 'oldpath' to 'newpath' */
|
||||
int do_hardlink(struct sftp_conn *, char *, char *);
|
||||
|
||||
/* Rename 'oldpath' to 'newpath' */
|
||||
int do_symlink(struct sftp_conn *, char *, char *);
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: sftp-server.c,v 1.92 2010/11/04 02:45:34 djm Exp $ */
|
||||
/* $OpenBSD: sftp-server.c,v 1.93 2010/12/04 00:18:01 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2000-2004 Markus Friedl. All rights reserved.
|
||||
*
|
||||
|
@ -535,6 +535,9 @@ process_init(void)
|
|||
/* fstatvfs extension */
|
||||
buffer_put_cstring(&msg, "fstatvfs@openssh.com");
|
||||
buffer_put_cstring(&msg, "2"); /* version */
|
||||
/* hardlink extension */
|
||||
buffer_put_cstring(&msg, "hardlink@openssh.com");
|
||||
buffer_put_cstring(&msg, "1"); /* version */
|
||||
send_msg(&msg);
|
||||
buffer_free(&msg);
|
||||
}
|
||||
|
@ -1222,6 +1225,27 @@ process_extended_fstatvfs(u_int32_t id)
|
|||
send_statvfs(id, &st);
|
||||
}
|
||||
|
||||
static void
|
||||
process_extended_hardlink(u_int32_t id)
|
||||
{
|
||||
char *oldpath, *newpath;
|
||||
int ret, status;
|
||||
|
||||
oldpath = get_string(NULL);
|
||||
newpath = get_string(NULL);
|
||||
debug3("request %u: hardlink", id);
|
||||
logit("hardlink old \"%s\" new \"%s\"", oldpath, newpath);
|
||||
if (readonly)
|
||||
status = SSH2_FX_PERMISSION_DENIED;
|
||||
else {
|
||||
ret = link(oldpath, newpath);
|
||||
status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
|
||||
}
|
||||
send_status(id, status);
|
||||
xfree(oldpath);
|
||||
xfree(newpath);
|
||||
}
|
||||
|
||||
static void
|
||||
process_extended(void)
|
||||
{
|
||||
|
@ -1236,6 +1260,8 @@ process_extended(void)
|
|||
process_extended_statvfs(id);
|
||||
else if (strcmp(request, "fstatvfs@openssh.com") == 0)
|
||||
process_extended_fstatvfs(id);
|
||||
else if (strcmp(request, "hardlink@openssh.com") == 0)
|
||||
process_extended_hardlink(id);
|
||||
else
|
||||
send_status(id, SSH2_FX_OP_UNSUPPORTED); /* MUST */
|
||||
xfree(request);
|
||||
|
|
18
sftp.1
18
sftp.1
|
@ -1,4 +1,4 @@
|
|||
.\" $OpenBSD: sftp.1,v 1.87 2010/11/18 15:01:00 jmc Exp $
|
||||
.\" $OpenBSD: sftp.1,v 1.88 2010/12/04 00:18:01 djm Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2001 Damien Miller. All rights reserved.
|
||||
.\"
|
||||
|
@ -22,7 +22,7 @@
|
|||
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd $Mdocdate: November 18 2010 $
|
||||
.Dd $Mdocdate: December 4 2010 $
|
||||
.Dt SFTP 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
|
@ -128,7 +128,7 @@ commands fail:
|
|||
.Ic get , put , rename , ln ,
|
||||
.Ic rm , mkdir , chdir , ls ,
|
||||
.Ic lchdir , chmod , chown ,
|
||||
.Ic chgrp , lpwd , df ,
|
||||
.Ic chgrp , lpwd , df , symlink ,
|
||||
and
|
||||
.Ic lmkdir .
|
||||
Termination on error can be suppressed on a command by command basis by
|
||||
|
@ -392,11 +392,19 @@ characters and may match multiple files.
|
|||
.It Ic lmkdir Ar path
|
||||
Create local directory specified by
|
||||
.Ar path .
|
||||
.It Ic ln Ar oldpath Ar newpath
|
||||
Create a symbolic link from
|
||||
.It Xo Ic ln
|
||||
.Op Fl s
|
||||
.Ar oldpath
|
||||
.Ar newpath
|
||||
.Xc
|
||||
Create a link from
|
||||
.Ar oldpath
|
||||
to
|
||||
.Ar newpath .
|
||||
If the
|
||||
.Fl s
|
||||
flag is specified the created link is a symbolic link, otherwise it is
|
||||
a hard link.
|
||||
.It Ic lpwd
|
||||
Print local working directory.
|
||||
.It Xo Ic ls
|
||||
|
|
53
sftp.c
53
sftp.c
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: sftp.c,v 1.131 2010/10/23 22:06:12 sthen Exp $ */
|
||||
/* $OpenBSD: sftp.c,v 1.132 2010/12/04 00:18:01 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
|
||||
*
|
||||
|
@ -132,6 +132,7 @@ extern char *__progname;
|
|||
#define I_GET 5
|
||||
#define I_HELP 6
|
||||
#define I_LCHDIR 7
|
||||
#define I_LINK 25
|
||||
#define I_LLS 8
|
||||
#define I_LMKDIR 9
|
||||
#define I_LPWD 10
|
||||
|
@ -176,7 +177,7 @@ static const struct CMD cmds[] = {
|
|||
{ "lchdir", I_LCHDIR, LOCAL },
|
||||
{ "lls", I_LLS, LOCAL },
|
||||
{ "lmkdir", I_LMKDIR, LOCAL },
|
||||
{ "ln", I_SYMLINK, REMOTE },
|
||||
{ "ln", I_LINK, REMOTE },
|
||||
{ "lpwd", I_LPWD, LOCAL },
|
||||
{ "ls", I_LS, REMOTE },
|
||||
{ "lumask", I_LUMASK, NOARGS },
|
||||
|
@ -240,7 +241,7 @@ help(void)
|
|||
"lcd path Change local directory to 'path'\n"
|
||||
"lls [ls-options [path]] Display local directory listing\n"
|
||||
"lmkdir path Create local directory\n"
|
||||
"ln oldpath newpath Symlink remote file\n"
|
||||
"ln [-s] oldpath newpath Link remote file (-s for symlink)\n"
|
||||
"lpwd Print local working directory\n"
|
||||
"ls [-1afhlnrSt] [path] Display remote directory listing\n"
|
||||
"lumask umask Set local umask to 'umask'\n"
|
||||
|
@ -376,6 +377,30 @@ parse_getput_flags(const char *cmd, char **argv, int argc, int *pflag,
|
|||
return optind;
|
||||
}
|
||||
|
||||
static int
|
||||
parse_link_flags(const char *cmd, char **argv, int argc, int *sflag)
|
||||
{
|
||||
extern int opterr, optind, optopt, optreset;
|
||||
int ch;
|
||||
|
||||
optind = optreset = 1;
|
||||
opterr = 0;
|
||||
|
||||
*sflag = 0;
|
||||
while ((ch = getopt(argc, argv, "s")) != -1) {
|
||||
switch (ch) {
|
||||
case 's':
|
||||
*sflag = 1;
|
||||
break;
|
||||
default:
|
||||
error("%s: Invalid flag -%c", cmd, optopt);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return optind;
|
||||
}
|
||||
|
||||
static int
|
||||
parse_ls_flags(char **argv, int argc, int *lflag)
|
||||
{
|
||||
|
@ -1088,7 +1113,7 @@ makeargv(const char *arg, int *argcp, int sloppy, char *lastquote,
|
|||
|
||||
static int
|
||||
parse_args(const char **cpp, int *pflag, int *rflag, int *lflag, int *iflag,
|
||||
int *hflag, unsigned long *n_arg, char **path1, char **path2)
|
||||
int *hflag, int *sflag, unsigned long *n_arg, char **path1, char **path2)
|
||||
{
|
||||
const char *cmd, *cp = *cpp;
|
||||
char *cp2, **argv;
|
||||
|
@ -1138,7 +1163,8 @@ parse_args(const char **cpp, int *pflag, int *rflag, int *lflag, int *iflag,
|
|||
switch (cmdnum) {
|
||||
case I_GET:
|
||||
case I_PUT:
|
||||
if ((optidx = parse_getput_flags(cmd, argv, argc, pflag, rflag)) == -1)
|
||||
if ((optidx = parse_getput_flags(cmd, argv, argc,
|
||||
pflag, rflag)) == -1)
|
||||
return -1;
|
||||
/* Get first pathname (mandatory) */
|
||||
if (argc - optidx < 1) {
|
||||
|
@ -1154,8 +1180,11 @@ parse_args(const char **cpp, int *pflag, int *rflag, int *lflag, int *iflag,
|
|||
undo_glob_escape(*path2);
|
||||
}
|
||||
break;
|
||||
case I_RENAME:
|
||||
case I_LINK:
|
||||
if ((optidx = parse_link_flags(cmd, argv, argc, sflag)) == -1)
|
||||
return -1;
|
||||
case I_SYMLINK:
|
||||
case I_RENAME:
|
||||
if (argc - optidx < 2) {
|
||||
error("You must specify two paths after a %s "
|
||||
"command.", cmd);
|
||||
|
@ -1258,7 +1287,8 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
|
|||
int err_abort)
|
||||
{
|
||||
char *path1, *path2, *tmp;
|
||||
int pflag = 0, rflag = 0, lflag = 0, iflag = 0, hflag = 0, cmdnum, i;
|
||||
int pflag = 0, rflag = 0, lflag = 0, iflag = 0, hflag = 0, sflag = 0;
|
||||
int cmdnum, i;
|
||||
unsigned long n_arg = 0;
|
||||
Attrib a, *aa;
|
||||
char path_buf[MAXPATHLEN];
|
||||
|
@ -1266,8 +1296,8 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
|
|||
glob_t g;
|
||||
|
||||
path1 = path2 = NULL;
|
||||
cmdnum = parse_args(&cmd, &pflag, &rflag, &lflag, &iflag, &hflag, &n_arg,
|
||||
&path1, &path2);
|
||||
cmdnum = parse_args(&cmd, &pflag, &rflag, &lflag, &iflag, &hflag,
|
||||
&sflag, &n_arg, &path1, &path2);
|
||||
|
||||
if (iflag != 0)
|
||||
err_abort = 0;
|
||||
|
@ -1295,8 +1325,11 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
|
|||
err = do_rename(conn, path1, path2);
|
||||
break;
|
||||
case I_SYMLINK:
|
||||
sflag = 1;
|
||||
case I_LINK:
|
||||
path1 = make_absolute(path1, *pwd);
|
||||
path2 = make_absolute(path2, *pwd);
|
||||
err = do_symlink(conn, path1, path2);
|
||||
err = (sflag ? do_symlink : do_hardlink)(conn, path1, path2);
|
||||
break;
|
||||
case I_RM:
|
||||
path1 = make_absolute(path1, *pwd);
|
||||
|
|
Loading…
Reference in New Issue