Add new file handle system calls.

Namely, getfhat(2), fhlink(2), fhlinkat(2), fhreadlink(2).  The
syscalls are provided for a NFS userspace server (nfs-ganesha).

Submitted by:	Jack Halford <jack@gandi.net>
Sponsored by:	Gandi.net
Tested by:	pho
Feedback from:	brooks, markj
MFC after:	1 week
Differential revision:	https://reviews.freebsd.org/D18359
This commit is contained in:
kib 2018-12-07 15:17:29 +00:00
parent 73f834bfbb
commit 48d91fd889
9 changed files with 716 additions and 48 deletions

View File

@ -184,7 +184,9 @@ MAN+= abort2.2 \
extattr_get_file.2 \
fcntl.2 \
ffclock.2 \
fhlink.2 \
fhopen.2 \
fhreadlink.2 \
flock.2 \
fork.2 \
fsync.2 \
@ -395,7 +397,8 @@ MLINKS+=ffclock.2 ffclock_getcounter.2 \
MLINKS+=fhopen.2 fhstat.2 fhopen.2 fhstatfs.2
MLINKS+=fsync.2 fdatasync.2
MLINKS+=getdirentries.2 getdents.2
MLINKS+=getfh.2 lgetfh.2
MLINKS+=getfh.2 lgetfh.2 \
getfh.2 getfhat.2
MLINKS+=getgid.2 getegid.2
MLINKS+=getitimer.2 setitimer.2
MLINKS+=getlogin.2 getlogin_r.3

View File

@ -401,6 +401,13 @@ FBSD_1.5 {
cpuset_setdomain;
};
FBSD_1.6 {
fhlink;
fhlinkat;
fhreadlink;
getfhat;
};
FBSDprivate_1.0 {
___acl_aclcheck_fd;
__sys___acl_aclcheck_fd;

268
lib/libc/sys/fhlink.2 Normal file
View File

@ -0,0 +1,268 @@
.\" SPDX-License-Identifier: BSD-2-Clause
.\"
.\" Copyright (c) 2018 Gandi
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" $FreeBSD$
.\"
.Dd November 29, 2018
.Dt FHLINK 2
.Os
.Sh NAME
.Nm fhlink ,
.Nm fhlinkat
.Nd make a hard file link
.Sh LIBRARY
.Lb libc
.Sh SYNOPSIS
.In unistd.h
.Ft int
.Fn fhlink "fhandle_t *fhp" "const char *to"
.Ft int
.Fn fhlinkat "fhandle_t *fhp" "int tofd" "const char *to"
.Fc
.Sh DESCRIPTION
The
.Fn fhlink
system call
atomically creates the specified directory entry (hard link)
.Fa to
with the attributes of the underlying object pointed at by
.Fa fhp .
If the link is successful: the link count of the underlying object
is incremented;
.Fa fhp
and
.Fa to
share equal access and rights
to the
underlying object.
.Pp
If
.Fa fhp
is removed, the file
.Fa to
is not deleted and the link count of the
underlying object is
decremented.
.Pp
The object pointed at by the
.Fa fhp
argument
must exist for the hard link to
succeed and
both
.Fa fhp
and
.Fa to
must be in the same file system.
The
.Fa fhp
argument
may not be a directory.
.Pp
The
.Fn fhlinkat
system call is equivalent to
.Fa fhlink
except in the case where
.Fa to
is a relative paths.
In this case a relative path
.Fa to
is interpreted relative to
the directory associated with the file descriptor
.Fa tofd
instead of the current working directory.
.Pp
Values for
.Fa flag
are constructed by a bitwise-inclusive OR of flags from the following
list, defined in
.In fcntl.h :
.Bl -tag -width indent
.It Dv AT_SYMLINK_FOLLOW
If
.Fa fhp
names a symbolic link, a new link for the target of the symbolic link is
created.
.It Dv AT_BENEATH
Only allow to link to a file which is beneath of the topping directory.
See the description of the
.Dv O_BENEATH
flag in the
.Xr open 2
manual page.
.El
.Pp
If
.Fn fhlinkat
is passed the special value
.Dv AT_FDCWD
in the
.Fa tofd
parameter, the current working directory is used for the
.Fa to
argument.
If
.Fa tofd
has value
.Dv AT_FDCWD ,
the behavior is identical to a call to
.Fn link .
Unless
.Fa flag
contains the
.Dv AT_SYMLINK_FOLLOW
flag, if
.Fa fhp
names a symbolic link, a new link is created for the symbolic link
.Fa fhp
and not its target.
.Sh RETURN VALUES
.Rv -std link
.Sh ERRORS
The
.Fn fhlink
system call
will fail and no link will be created if:
.Bl -tag -width Er
.It Bq Er ENOTDIR
A component of
.Fa to
prefix is not a directory.
.It Bq Er ENAMETOOLONG
A component of
.Fa to
exceeded 255 characters,
or entire length of
.Fa to
name exceeded 1023 characters.
.It Bq Er ENOENT
A component of
.Fa to
prefix does not exist.
.It Bq Er EOPNOTSUPP
The file system containing the file pointed at by
.Fa fhp
does not support links.
.It Bq Er EMLINK
The link count of the file pointed at by
.Fa fhp
would exceed 32767.
.It Bq Er EACCES
A component of
.Fa to
prefix denies search permission.
.It Bq Er EACCES
The requested link requires writing in a directory with a mode
that denies write permission.
.It Bq Er ELOOP
Too many symbolic links were encountered in translating one of the pathnames.
.It Bq Er ENOENT
The file pointed at by
.Fa fhp
does not exist.
.It Bq Er EEXIST
The link named by
.Fa to
does exist.
.It Bq Er EPERM
The file pointed at by
.Fa fhp
is a directory.
.It Bq Er EPERM
The file pointed at by
.Fa fhp
has its immutable or append-only flag set, see the
.Xr chflags 2
manual page for more information.
.It Bq Er EPERM
The parent directory of the file named by
.Fa to
has its immutable flag set.
.It Bq Er EXDEV
The link named by
.Fa to
and the file pointed at by
.Fa fhp
are on different file systems.
.It Bq Er ENOSPC
The directory in which the entry for the new link is being placed
cannot be extended because there is no space left on the file
system containing the directory.
.It Bq Er EDQUOT
The directory in which the entry for the new link
is being placed cannot be extended because the
user's quota of disk blocks on the file system
containing the directory has been exhausted.
.It Bq Er EIO
An I/O error occurred while reading from or writing to
the file system to make the directory entry.
.It Bq Er EROFS
The requested link requires writing in a directory on a read-only file
system.
.It Bq Er EFAULT
One of the pathnames specified
is outside the process's allocated address space.
.It Bq Er ESTALE
The file handle
.Fa fhp
is no longer valid
.El
.Pp
In addition to the errors returned by the
.Fn fhlink ,
the
.Fn fhlinkat
system call may fail if:
.Bl -tag -width Er
.It Bq Er EBADF
The
.Fa fhp
or
.Fa to
argument does not specify an absolute path and the
.Fa tofd
argument, is not
.Dv AT_FDCWD
nor a valid file descriptor open for searching.
.It Bq Er EINVAL
The value of the
.Fa flag
argument is not valid.
.It Bq Er ENOTDIR
The
.Fa fhp
or
.Fa to
argument is not an absolute path and
.Fa tofd
is not
.Dv AT_FDCWD
nor a file descriptor associated with a directory.
.El
.Sh SEE ALSO
.Xr fhstat 2 ,
.Xr fhreadlink 2 ,
.Xr fhopen 2 ,

92
lib/libc/sys/fhreadlink.2 Normal file
View File

@ -0,0 +1,92 @@
.\" SPDX-License-Identifier: BSD-2-Clause
.\"
.\" Copyright (c) 2018 Gandi
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" $FreeBSD$
.\"
.Dd November 29, 2018
.Dt FHREADLINK 2
.Os
.Sh NAME
.Nm fhreadlink
.Nd read value of a symbolic link
.Sh LIBRARY
.Lb libc
.Sh SYNOPSIS
.In sys/param.h
.In sys/mount.h
.Ft int
.Fn fhreadlink "fhandle_t *fhp" "char *buf" "size_t bufsize"
.Fc
.Sh DESCRIPTION
The
.Fn fhreadlink
system call
places the contents of the symbolic link
.Fa fhp
in the buffer
.Fa buf ,
which has size
.Fa bufsiz .
The
.Fn fhreadlink
system call does not append a
.Dv NUL
character to
.Fa buf .
.Pp
.Sh RETURN VALUES
The call returns the count of characters placed in the buffer
if it succeeds, or a \-1 if an error occurs, placing the error
code in the global variable
.Va errno .
.Sh ERRORS
The
.Fn readlink
system call
will fail if:
.Bl -tag -width Er
.It Bq Er ENOENT
The named file does not exist.
.It Bq Er ELOOP
Too many symbolic links were encountered in translating the file handle
.Fa fhp .
.It Bq Er EINVAL
The named file is not a symbolic link.
.It Bq Er EIO
An I/O error occurred while reading from the file system.
.It Bq Er EFAULT
The
.Fa buf
argument
extends outside the process's allocated address space.
.It Bq Er ESTALE
The file handle
.Fa fhp
is no longer valid
.El
.El
.Sh SEE ALSO
.Xr fhstat 2 ,
.Xr fhlink 2 ,

View File

@ -1,5 +1,6 @@
.\" Copyright (c) 1989, 1991, 1993
.\" The Regents of the University of California. All rights reserved.
.\" Copyright (c) 2018 Gandi
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
@ -28,12 +29,13 @@
.\" @(#)getfh.2 8.1 (Berkeley) 6/9/93
.\" $FreeBSD$
.\"
.Dd April 14, 2011
.Dd December 7, 2018
.Dt GETFH 2
.Os
.Sh NAME
.Nm getfh ,
.Nm lgetfh
.Nm lgetfh ,
.Nm getfhat
.Nd get file handle
.Sh LIBRARY
.Lb libc
@ -44,6 +46,8 @@
.Fn getfh "const char *path" "fhandle_t *fhp"
.Ft int
.Fn lgetfh "const char *path" "fhandle_t *fhp"
.Ft int
.Fn getfhat "int fd" "const char *path" "fhandle_t *fhp" "int flag"
.Sh DESCRIPTION
The
.Fn getfh
@ -51,6 +55,7 @@ system call
returns a file handle for the specified file or directory
in the file handle pointed to by
.Fa fhp .
.Pp
The
.Fn lgetfh
system call is like
@ -62,6 +67,85 @@ returns information about the link,
while
.Fn getfh
returns information about the file the link references.
.Pp
The
.Fn getfhat
system call is equivalent to
.Fn getfh
and
.Fn lgetfh
except when the
.Fa path
specifies a relative or NULL path, or the
.Dv AT_BENEATH
flag is provided.
For
.Fn getfhat
and relative or NULL
.Fa path ,
the status is retrieved from a file relative to
the directory associated with the file descriptor
.Fa fd
instead of the current working directory.
For
.Dv AT_BENEATH
and absolute
.Fa path ,
the status is retrieved from a file specified by the
.Fa path ,
but additional permission checks are performed, see below.
.Pp
The values for the
.Fa flag
are constructed by a bitwise-inclusive OR of flags from this list,
defined in
.In fcntl.h :
.Bl -tag -width indent
.It Dv AT_SYMLINK_NOFOLLOW
If
.Fa path
names a symbolic link, the status of the symbolic link is returned.
.It Dv AT_BENEATH
Only stat files and directories below the topping directory.
See the description of the
.Dv O_BENEATH
flag in the
.Xr open 2
manual page.
.El
.Pp
If
.Fn getfhat
is passed the special value
.Dv AT_FDCWD
in the
.Fa fd
parameter, the current working directory is used and the behavior is
identical to a call to
.Fn getfth
or
.Fn lgetfh
respectively, depending on whether or not the
.Dv AT_SYMLINK_NOFOLLOW
bit is set in
.Fa flag .
.Pp
When
.Fn getfhat
is called with an absolute
.Fa path
without the
.Dv AT_BENEATH
flag, it ignores the
.Fa fd
argument.
When
.Dv AT_BENEATH
is specified with an absolute
.Fa path ,
a directory passed by the
.Fa fd
argument is used as the topping point for the resolution.
These system calls are restricted to the superuser.
.Sh RETURN VALUES
.Rv -std
@ -99,11 +183,49 @@ The
.Fa fhp
argument
points to an invalid address.
.It Bq Er EFAULT
The
.Fa path
argument
points to an invalid address.
.It Bq Er EIO
An
.Tn I/O
error occurred while reading from or writing to the file system.
.It Bq Er ESTALE
The file handle
.Fa fhp
is no longer valid.
.El
.Pp
In addition to the errors returned by
.Fn getfh ,
and
.Fn lgetfh ,
the
.Fn getfhat
system call may fail if:
.Bl -tag -width Er
.It Bq Er EBADF
The
.Fa path
argument does not specify an absolute path and the
.Fa fd
argument, is neither
.Dv AT_FDCWD
nor a valid file descriptor open for searching.
.It Bq Er EINVAL
The value of the
.Fa flag
argument is not valid.
.It Bq Er ENOTDIR
The
.Fa path
argument is not an absolute path and
.Fa fd
is neither
.Dv AT_FDCWD
nor a file descriptor associated with a directory.
.Sh SEE ALSO
.Xr fhopen 2 ,
.Xr open 2 ,

View File

@ -1138,5 +1138,12 @@
int policy); }
563 AUE_NULL NOPROTO { int getrandom(void *buf, size_t buflen, \
unsigned int flags); }
564 AUE_NULL NOPROTO { int getfhat( int fd, char *path, \
struct fhandle *fhp, int flags); }
565 AUE_NULL NOPROTO { int fhlink( struct fhandle *fhp, const char *to ); }
566 AUE_NULL NOPROTO { int fhlinkat( struct fhandle *fhp, int tofd, \
const char *to); }
567 AUE_NULL NOPROTO { int fhreadlink( struct fhandle *fhp, char *buf, \
size_t bufsize); }
; vim: syntax=off

View File

@ -3139,6 +3139,34 @@
unsigned int flags
);
}
564 AUE_NULL STD {
int getfhat(
int fd,
_In_z_ char *path,
_Out_ struct fhandle *fhp,
int flags
);
}
565 AUE_NULL STD {
int fhlink(
_In_ struct fhandle *fhp,
_In_z_ const char *to
);
}
566 AUE_NULL STD {
int fhlinkat(
_In_ struct fhandle *fhp,
int tofd,
_In_z_ const char *to,
);
}
567 AUE_NULL STD {
int fhreadlink(
_In_ struct fhandle *fhp,
_Out_writes_(bufsize) char *buf,
size_t bufsize
);
}
; Please copy any additions and changes to the following compatability tables:
; sys/compat/freebsd32/syscalls.master

View File

@ -105,6 +105,14 @@ static int setutimes(struct thread *td, struct vnode *,
const struct timespec *, int, int);
static int vn_access(struct vnode *vp, int user_flags, struct ucred *cred,
struct thread *td);
static int kern_fhlinkat(struct thread *td, int fd, const char *path,
enum uio_seg pathseg, fhandle_t *fhp);
static int kern_getfhat(struct thread *td, int flags, int fd,
const char *path, enum uio_seg pathseg, fhandle_t *fhp);
static int kern_readlink_vp(struct vnode *vp, char *buf, enum uio_seg bufseg,
size_t count, struct thread *td);
static int kern_linkat_vp(struct thread *td, struct vnode *vp, int fd,
const char *path, enum uio_seg segflag);
/*
* Sync each mounted filesystem.
@ -1492,28 +1500,38 @@ can_hardlink(struct vnode *vp, struct ucred *cred)
int
kern_linkat(struct thread *td, int fd1, int fd2, const char *path1,
const char *path2, enum uio_seg segflg, int follow)
const char *path2, enum uio_seg segflag, int follow)
{
struct vnode *vp;
struct mount *mp;
struct nameidata nd;
int error;
again:
bwillwrite();
NDINIT_ATRIGHTS(&nd, LOOKUP, follow | AUDITVNODE1, segflg, path1, fd1,
&cap_linkat_source_rights, td);
do {
bwillwrite();
NDINIT_ATRIGHTS(&nd, LOOKUP, follow | AUDITVNODE1, segflag, path1, fd1,
&cap_linkat_source_rights, td);
if ((error = namei(&nd)) != 0)
return (error);
NDFREE(&nd, NDF_ONLY_PNBUF);
vp = nd.ni_vp;
} while ((error = kern_linkat_vp(td, vp, fd2, path2, segflag) == EAGAIN));
return (error);
}
static int
kern_linkat_vp(struct thread *td, struct vnode *vp, int fd, const char *path,
enum uio_seg segflag)
{
struct nameidata nd;
struct mount *mp;
int error;
if ((error = namei(&nd)) != 0)
return (error);
NDFREE(&nd, NDF_ONLY_PNBUF);
vp = nd.ni_vp;
if (vp->v_type == VDIR) {
vrele(vp);
return (EPERM); /* POSIX */
}
NDINIT_ATRIGHTS(&nd, CREATE,
LOCKPARENT | SAVENAME | AUDITVNODE2 | NOCACHE, segflg, path2, fd2,
LOCKPARENT | SAVENAME | AUDITVNODE2 | NOCACHE, segflag, path, fd,
&cap_linkat_target_rights, td);
if ((error = namei(&nd)) == 0) {
if (nd.ni_vp != NULL) {
@ -1557,7 +1575,7 @@ kern_linkat(struct thread *td, int fd1, int fd2, const char *path1,
V_XSLEEP | PCATCH);
if (error != 0)
return (error);
goto again;
return (EAGAIN);
}
error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
VOP_UNLOCK(vp, 0);
@ -1568,7 +1586,7 @@ kern_linkat(struct thread *td, int fd1, int fd2, const char *path1,
vput(nd.ni_dvp);
NDFREE(&nd, NDF_ONLY_PNBUF);
vrele(vp);
goto again;
return (EAGAIN);
}
}
vrele(vp);
@ -2484,8 +2502,6 @@ kern_readlinkat(struct thread *td, int fd, const char *path,
enum uio_seg pathseg, char *buf, enum uio_seg bufseg, size_t count)
{
struct vnode *vp;
struct iovec aiov;
struct uio auio;
struct nameidata nd;
int error;
@ -2499,12 +2515,29 @@ kern_readlinkat(struct thread *td, int fd, const char *path,
return (error);
NDFREE(&nd, NDF_ONLY_PNBUF);
vp = nd.ni_vp;
error = kern_readlink_vp(vp, buf, bufseg, count, td);
vput(vp);
return (error);
}
/*
* Helper function to readlink from a vnode
*/
static int
kern_readlink_vp(struct vnode *vp, char *buf, enum uio_seg bufseg, size_t count,
struct thread *td)
{
struct iovec aiov;
struct uio auio;
int error;
ASSERT_VOP_LOCKED(vp, "kern_readlink_vp(): vp not locked");
#ifdef MAC
error = mac_vnode_check_readlink(td->td_ucred, vp);
if (error != 0) {
vput(vp);
if (error != 0)
return (error);
}
#endif
if (vp->v_type != VLNK && (vp->v_vflag & VV_READLINK) == 0)
error = EINVAL;
@ -2521,7 +2554,6 @@ kern_readlinkat(struct thread *td, int fd, const char *path,
error = VOP_READLINK(vp, &auio, td->td_ucred);
td->td_retval[0] = count - auio.uio_resid;
}
vput(vp);
return (error);
}
@ -4119,45 +4151,60 @@ getvnode(struct thread *td, int fd, cap_rights_t *rightsp, struct file **fpp)
*/
#ifndef _SYS_SYSPROTO_H_
struct lgetfh_args {
char *fname;
char *fname;
fhandle_t *fhp;
};
#endif
int
sys_lgetfh(struct thread *td, struct lgetfh_args *uap)
{
struct nameidata nd;
fhandle_t fh;
struct vnode *vp;
int error;
error = priv_check(td, PRIV_VFS_GETFH);
if (error != 0)
return (error);
NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | AUDITVNODE1, UIO_USERSPACE,
uap->fname, td);
error = namei(&nd);
if (error != 0)
return (error);
NDFREE(&nd, NDF_ONLY_PNBUF);
vp = nd.ni_vp;
bzero(&fh, sizeof(fh));
fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid;
error = VOP_VPTOFH(vp, &fh.fh_fid);
vput(vp);
if (error == 0)
error = copyout(&fh, uap->fhp, sizeof (fh));
return (error);
return (kern_getfhat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, uap->fname,
UIO_USERSPACE, uap->fhp));
}
#ifndef _SYS_SYSPROTO_H_
struct getfh_args {
char *fname;
char *fname;
fhandle_t *fhp;
};
#endif
int
sys_getfh(struct thread *td, struct getfh_args *uap)
{
return (kern_getfhat(td, 0, AT_FDCWD, uap->fname, UIO_USERSPACE,
uap->fhp));
}
/*
* syscall for the rpc.lockd to use to translate an open descriptor into
* a NFS file handle.
*
* warning: do not remove the priv_check() call or this becomes one giant
* security hole.
*/
#ifndef _SYS_SYSPROTO_H_
struct getfhat_args {
int fd;
char *path;
fhandle_t *fhp;
int flags;
};
#endif
int
sys_getfhat(struct thread *td, struct getfhat_args *uap)
{
if ((uap->flags & ~(AT_SYMLINK_NOFOLLOW | AT_BENEATH)) != 0)
return (EINVAL);
return (kern_getfhat(td, uap->flags, uap->fd, uap->path ? uap->path : ".",
UIO_USERSPACE, uap->fhp));
}
static int
kern_getfhat(struct thread *td, int flags, int fd, const char *path,
enum uio_seg pathseg, fhandle_t *fhp)
{
struct nameidata nd;
fhandle_t fh;
@ -4167,8 +4214,9 @@ sys_getfh(struct thread *td, struct getfh_args *uap)
error = priv_check(td, PRIV_VFS_GETFH);
if (error != 0)
return (error);
NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNODE1, UIO_USERSPACE,
uap->fname, td);
NDINIT_AT(&nd, LOOKUP, ((flags & AT_SYMLINK_NOFOLLOW) != 0 ? NOFOLLOW :
FOLLOW) | ((flags & AT_BENEATH) != 0 ? BENEATH : 0) | LOCKLEAF |
AUDITVNODE1, pathseg, path, fd, td);
error = namei(&nd);
if (error != 0)
return (error);
@ -4179,7 +4227,96 @@ sys_getfh(struct thread *td, struct getfh_args *uap)
error = VOP_VPTOFH(vp, &fh.fh_fid);
vput(vp);
if (error == 0)
error = copyout(&fh, uap->fhp, sizeof (fh));
error = copyout(&fh, fhp, sizeof (fh));
return (error);
}
#ifndef _SYS_SYSPROTO_H_
struct fhlink_args {
fhandle_t *fhp;
const char *to;
};
#endif
int
sys_fhlink(struct thread *td, struct fhlink_args *uap)
{
return (kern_fhlinkat(td, AT_FDCWD, uap->to, UIO_USERSPACE, uap->fhp));
}
#ifndef _SYS_SYSPROTO_H_
struct fhlinkat_args {
fhandle_t *fhp;
int tofd;
const char *to;
};
#endif
int
sys_fhlinkat(struct thread *td, struct fhlinkat_args *uap)
{
return (kern_fhlinkat(td, uap->tofd, uap->to, UIO_USERSPACE, uap->fhp));
}
static int
kern_fhlinkat(struct thread *td, int fd, const char *path,
enum uio_seg pathseg, fhandle_t *fhp)
{
fhandle_t fh;
struct mount *mp;
struct vnode *vp;
int error;
error = priv_check(td, PRIV_VFS_GETFH);
if (error != 0)
return (error);
error = copyin(fhp, &fh, sizeof(fh));
if (error != 0)
return (error);
do {
bwillwrite();
if ((mp = vfs_busyfs(&fh.fh_fsid)) == NULL)
return (ESTALE);
error = VFS_FHTOVP(mp, &fh.fh_fid, LK_SHARED, &vp);
vfs_unbusy(mp);
if (error != 0)
return (error);
VOP_UNLOCK(vp, 0);
} while ((error = kern_linkat_vp(td, vp, fd, path, pathseg)) == EAGAIN);
return (error);
}
#ifndef _SYS_SYSPROTO_H_
struct fhreadlink_args {
fhandle_t *fhp;
char *buf;
size_t bufsize;
};
#endif
int
sys_fhreadlink(struct thread *td, struct fhreadlink_args *uap)
{
fhandle_t fh;
struct mount *mp;
struct vnode *vp;
int error;
error = priv_check(td, PRIV_VFS_GETFH);
if (error != 0)
return (error);
if (uap->bufsize > IOSIZE_MAX)
return (EINVAL);
error = copyin(uap->fhp, &fh, sizeof(fh));
if (error != 0)
return (error);
if ((mp = vfs_busyfs(&fh.fh_fsid)) == NULL)
return (ESTALE);
error = VFS_FHTOVP(mp, &fh.fh_fid, LK_SHARED, &vp);
vfs_unbusy(mp);
if (error != 0)
return (error);
error = kern_readlink_vp(vp, uap->buf, UIO_USERSPACE, uap->bufsize, td);
vput(vp);
return (error);
}

View File

@ -932,11 +932,15 @@ void syncer_resume(void);
struct stat;
__BEGIN_DECLS
int fhlink(struct fhandle *, const char *);
int fhlinkat(struct fhandle *, int, const char *);
int fhopen(const struct fhandle *, int);
int fhreadlink(struct fhandle *, char *, size_t);
int fhstat(const struct fhandle *, struct stat *);
int fhstatfs(const struct fhandle *, struct statfs *);
int fstatfs(int, struct statfs *);
int getfh(const char *, fhandle_t *);
int getfhat(int, char *, struct fhandle *, int);
int getfsstat(struct statfs *, long, int);
int getmntinfo(struct statfs **, int);
int lgetfh(const char *, fhandle_t *);