Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F133035202
D14567.id52946.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
14 KB
Referenced Files
None
Subscribers
None
D14567.id52946.diff
View Options
Index: include/unistd.h
===================================================================
--- include/unistd.h
+++ include/unistd.h
@@ -585,6 +585,7 @@
int undelete(const char *);
int unwhiteout(const char *);
void *valloc(size_t); /* obsoleted by malloc() */
+int funlinkat(int, const char *, int, int);
#ifndef _OPTRESET_DECLARED
#define _OPTRESET_DECLARED
Index: lib/libc/sys/Makefile.inc
===================================================================
--- lib/libc/sys/Makefile.inc
+++ lib/libc/sys/Makefile.inc
@@ -485,6 +485,7 @@
MLINKS+=thr_kill.2 thr_kill2.2
MLINKS+=truncate.2 ftruncate.2
MLINKS+=unlink.2 unlinkat.2
+MLINKS+=unlink.2 funlinkat.2
MLINKS+=utimensat.2 futimens.2
MLINKS+=utimes.2 futimes.2 \
utimes.2 futimesat.2 \
Index: lib/libc/sys/Symbol.map
===================================================================
--- lib/libc/sys/Symbol.map
+++ lib/libc/sys/Symbol.map
@@ -406,6 +406,7 @@
fhlinkat;
fhreadlink;
getfhat;
+ funlinkat;
};
FBSDprivate_1.0 {
Index: lib/libc/sys/unlink.2
===================================================================
--- lib/libc/sys/unlink.2
+++ lib/libc/sys/unlink.2
@@ -28,7 +28,7 @@
.\" @(#)unlink.2 8.1 (Berkeley) 6/4/93
.\" $FreeBSD$
.\"
-.Dd November 11, 2018
+.Dd January 16, 2019
.Dt UNLINK 2
.Os
.Sh NAME
@@ -42,7 +42,9 @@
.Ft int
.Fn unlink "const char *path"
.Ft int
-.Fn unlinkat "int fd" "const char *path" "int flag"
+.Fn unlinkat "int dfd" "const char *path" "int flag"
+.Ft int
+.Fn funlinkat "int dfd" "const char *path" "int fd" "int flag"
.Sh DESCRIPTION
The
.Fn unlink
@@ -74,7 +76,7 @@
specifies a relative path.
In this case the directory entry to be removed is determined
relative to the directory associated with the file descriptor
-.Fa fd
+.Fa dfd
instead of the current working directory.
.Pp
The values for
@@ -113,6 +115,26 @@
respectively, depending on whether or not the
.Dv AT_REMOVEDIR
bit is set in flag.
+.Pp
+The
+.Fn funlinkat
+system call can be used to unlink an already-opened file, unless that
+file has been replaced since it was opened.
+It is equivalent to
+.Fn unlinkat
+in the case where
+.Fa path
+is already open as the file descriptor
+.Fa fd .
+Otherwise, the path will not be removed and an error will be returned.
+The
+.Fa fd
+can be set the
+.Dv FD_NONE
+in that case
+.Fn funlinkat
+behaves exactly like
+.Fn unlinkat .
.Sh RETURN VALUES
.Rv -std unlink
.Sh ERRORS
@@ -227,6 +249,15 @@
.Fa path
escapes it.
.El
+.Pp
+In addition to the errors returned by the
+.Fn unlinkat ,
+.Fn funlinkat
+may fail if:
+.Bl -tag -width Er
+.It Bq Er EDEADLK
+The file descriptor is not associated with the path.
+.El
.Sh SEE ALSO
.Xr chflags 2 ,
.Xr close 2 ,
@@ -246,6 +277,10 @@
.Fn unlinkat
system call appeared in
.Fx 8.0 .
+The
+.Fn funlinkat
+system call appeared in
+.Fx 12.0 .
.Pp
The
.Fn unlink
Index: sys/cddl/compat/opensolaris/sys/vnode.h
===================================================================
--- sys/cddl/compat/opensolaris/sys/vnode.h
+++ sys/cddl/compat/opensolaris/sys/vnode.h
@@ -278,7 +278,8 @@
ASSERT(seg == UIO_SYSSPACE);
ASSERT(dirflag == RMFILE);
- return (kern_unlinkat(curthread, AT_FDCWD, fnamep, seg, 0, 0));
+ return (kern_funlinkat(curthread, AT_FDCWD, fnamep, FD_NONE, seg, 0,
+ 0));
}
#endif /* _KERNEL */
Index: sys/compat/cloudabi/cloudabi_file.c
===================================================================
--- sys/compat/cloudabi/cloudabi_file.c
+++ sys/compat/cloudabi/cloudabi_file.c
@@ -752,9 +752,11 @@
return (error);
if (uap->flags & CLOUDABI_UNLINK_REMOVEDIR)
- error = kern_rmdirat(td, uap->fd, path, UIO_SYSSPACE, 0);
+ error = kern_frmdirat(td, uap->fd, path, FD_NONE,
+ UIO_SYSSPACE, 0);
else
- error = kern_unlinkat(td, uap->fd, path, UIO_SYSSPACE, 0, 0);
+ error = kern_funlinkat(td, uap->fd, path, FD_NONE,
+ UIO_SYSSPACE, 0, 0);
cloudabi_freestr(path);
return (error);
}
Index: sys/compat/freebsd32/syscalls.master
===================================================================
--- sys/compat/freebsd32/syscalls.master
+++ sys/compat/freebsd32/syscalls.master
@@ -1145,5 +1145,7 @@
const char *to); }
567 AUE_NULL NOPROTO { int fhreadlink( struct fhandle *fhp, char *buf, \
size_t bufsize); }
+568 AUE_UNLINKAT NOPROTO { int funlinkat(int dfd, const char *path, int fd, \
+ int flag); }
; vim: syntax=off
Index: sys/compat/linux/linux_file.c
===================================================================
--- sys/compat/linux/linux_file.c
+++ sys/compat/linux/linux_file.c
@@ -590,7 +590,7 @@
printf(ARGS(unlink, "%s"), path);
#endif
- error = kern_unlinkat(td, AT_FDCWD, path, UIO_SYSSPACE, 0, 0);
+ error = kern_funlinkat(td, AT_FDCWD, path, FD_NONE, UIO_SYSSPACE, 0, 0);
if (error == EPERM) {
/* Introduce POSIX noncompliant behaviour of Linux */
if (kern_statat(td, 0, AT_FDCWD, path, UIO_SYSSPACE, &st,
@@ -623,9 +623,10 @@
#endif
if (args->flag & LINUX_AT_REMOVEDIR)
- error = kern_rmdirat(td, dfd, path, UIO_SYSSPACE, 0);
+ error = kern_frmdirat(td, dfd, path, FD_NONE, UIO_SYSSPACE, 0);
else
- error = kern_unlinkat(td, dfd, path, UIO_SYSSPACE, 0, 0);
+ error = kern_funlinkat(td, dfd, path, FD_NONE, UIO_SYSSPACE, 0,
+ 0);
if (error == EPERM && !(args->flag & LINUX_AT_REMOVEDIR)) {
/* Introduce POSIX noncompliant behaviour of Linux */
if (kern_statat(td, AT_SYMLINK_NOFOLLOW, dfd, path,
@@ -741,7 +742,7 @@
if (ldebug(rmdir))
printf(ARGS(rmdir, "%s"), path);
#endif
- error = kern_rmdirat(td, AT_FDCWD, path, UIO_SYSSPACE, 0);
+ error = kern_frmdirat(td, AT_FDCWD, path, FD_NONE, UIO_SYSSPACE, 0);
LFREEPATH(path);
return (error);
}
Index: sys/kern/capabilities.conf
===================================================================
--- sys/kern/capabilities.conf
+++ sys/kern/capabilities.conf
@@ -468,6 +468,7 @@
renameat
symlinkat
unlinkat
+funlinkat
utimensat
##
Index: sys/kern/syscalls.master
===================================================================
--- sys/kern/syscalls.master
+++ sys/kern/syscalls.master
@@ -3167,6 +3167,14 @@
size_t bufsize
);
}
+568 AUE_UNLINKAT STD {
+ int funlinkat(
+ int dfd,
+ _In_z_ const char *path,
+ int fd,
+ int flag
+ );
+ }
; Please copy any additions and changes to the following compatability tables:
; sys/compat/freebsd32/syscalls.master
Index: sys/kern/vfs_mountroot.c
===================================================================
--- sys/kern/vfs_mountroot.c
+++ sys/kern/vfs_mountroot.c
@@ -389,7 +389,7 @@
if (mporoot == mpdevfs) {
vfs_unbusy(mpdevfs);
/* Unlink the no longer needed /dev/dev -> / symlink */
- error = kern_unlinkat(td, AT_FDCWD, "/dev/dev",
+ error = kern_funlinkat(td, AT_FDCWD, "/dev/dev", FD_NONE,
UIO_SYSSPACE, 0, 0);
if (error)
printf("mountroot: unable to unlink /dev/dev "
Index: sys/kern/vfs_syscalls.c
===================================================================
--- sys/kern/vfs_syscalls.c
+++ sys/kern/vfs_syscalls.c
@@ -1751,7 +1751,22 @@
sys_unlink(struct thread *td, struct unlink_args *uap)
{
- return (kern_unlinkat(td, AT_FDCWD, uap->path, UIO_USERSPACE, 0, 0));
+ return (kern_funlinkat(td, AT_FDCWD, uap->path, FD_NONE, UIO_USERSPACE,
+ 0, 0));
+}
+
+static int
+kern_funlinkat_ex(struct thread *td, int dfd, const char *path, int fd,
+ int flag, enum uio_seg pathseg, ino_t oldinum)
+{
+
+ if ((flag & ~AT_REMOVEDIR) != 0)
+ return (EINVAL);
+
+ if ((flag & AT_REMOVEDIR) != 0)
+ return (kern_frmdirat(td, dfd, path, fd, UIO_USERSPACE, 0));
+
+ return (kern_funlinkat(td, dfd, path, fd, UIO_USERSPACE, 0, 0));
}
#ifndef _SYS_SYSPROTO_H_
@@ -1764,46 +1779,66 @@
int
sys_unlinkat(struct thread *td, struct unlinkat_args *uap)
{
- int fd, flag;
- const char *path;
- flag = uap->flag;
- fd = uap->fd;
- path = uap->path;
+ return (kern_funlinkat_ex(td, uap->fd, uap->path, FD_NONE, uap->flag,
+ UIO_USERSPACE, 0));
+}
- if ((flag & ~(AT_REMOVEDIR | AT_BENEATH)) != 0)
- return (EINVAL);
+#ifndef _SYS_SYSPROTO_H_
+struct funlinkat_args {
+ int dfd;
+ const char *path;
+ int fd;
+ int flag;
+};
+#endif
+int
+sys_funlinkat(struct thread *td, struct funlinkat_args *uap)
+{
- if ((uap->flag & AT_REMOVEDIR) != 0)
- return (kern_rmdirat(td, fd, path, UIO_USERSPACE, flag));
- else
- return (kern_unlinkat(td, fd, path, UIO_USERSPACE, flag, 0));
+ return (kern_funlinkat_ex(td, uap->dfd, uap->path, uap->fd, uap->flag,
+ UIO_USERSPACE, 0));
}
int
-kern_unlinkat(struct thread *td, int fd, const char *path,
+kern_funlinkat(struct thread *td, int dfd, const char *path, int fd,
enum uio_seg pathseg, int flag, ino_t oldinum)
{
struct mount *mp;
+ struct file *fp;
struct vnode *vp;
struct nameidata nd;
struct stat sb;
+ cap_rights_t rights;
int error;
+ fp = NULL;
+ if (fd != FD_NONE) {
+ error = getvnode(td, fd, cap_rights_init(&rights, CAP_LOOKUP),
+ &fp);
+ if (error != 0)
+ return (error);
+ }
+
restart:
bwillwrite();
NDINIT_ATRIGHTS(&nd, DELETE, LOCKPARENT | LOCKLEAF | AUDITVNODE1 |
((flag & AT_BENEATH) != 0 ? BENEATH : 0),
- pathseg, path, fd, &cap_unlinkat_rights, td);
- if ((error = namei(&nd)) != 0)
- return (error == EINVAL ? EPERM : error);
+ pathseg, path, dfd, &cap_unlinkat_rights, td);
+ if ((error = namei(&nd)) != 0) {
+ if (error == EINVAL)
+ error = EPERM;
+ goto fdout;
+ }
vp = nd.ni_vp;
if (vp->v_type == VDIR && oldinum == 0) {
error = EPERM; /* POSIX */
} else if (oldinum != 0 &&
((error = vn_stat(vp, &sb, td->td_ucred, NOCRED, td)) == 0) &&
sb.st_ino != oldinum) {
- error = EIDRM; /* Identifier removed */
+ error = EIDRM; /* Identifier removed */
+ } else if (fp != NULL && fp->f_vnode != vp) {
+ error = EDEADLK;
} else {
/*
* The root of a mounted filesystem cannot be deleted.
@@ -1822,8 +1857,9 @@
else
vput(vp);
if ((error = vn_start_write(NULL, &mp,
- V_XSLEEP | PCATCH)) != 0)
- return (error);
+ V_XSLEEP | PCATCH)) != 0) {
+ goto fdout;
+ }
goto restart;
}
#ifdef MAC
@@ -1845,6 +1881,9 @@
vrele(vp);
else
vput(vp);
+fdout:
+ if (fp != NULL)
+ fdrop(fp, td);
return (error);
}
@@ -3704,25 +3743,36 @@
sys_rmdir(struct thread *td, struct rmdir_args *uap)
{
- return (kern_rmdirat(td, AT_FDCWD, uap->path, UIO_USERSPACE, 0));
+ return (kern_frmdirat(td, AT_FDCWD, uap->path, FD_NONE, UIO_USERSPACE,
+ 0));
}
int
-kern_rmdirat(struct thread *td, int fd, const char *path, enum uio_seg pathseg,
- int flag)
+kern_frmdirat(struct thread *td, int dfd, const char *path, int fd,
+ enum uio_seg pathseg, int flag)
{
struct mount *mp;
struct vnode *vp;
+ struct file *fp;
struct nameidata nd;
+ cap_rights_t rights;
int error;
+ fp = NULL;
+ if (fd != FD_NONE) {
+ error = getvnode(td, fd, cap_rights_init(&rights, CAP_LOOKUP),
+ &fp);
+ if (error != 0)
+ return (error);
+ }
+
restart:
bwillwrite();
NDINIT_ATRIGHTS(&nd, DELETE, LOCKPARENT | LOCKLEAF | AUDITVNODE1 |
((flag & AT_BENEATH) != 0 ? BENEATH : 0),
- pathseg, path, fd, &cap_unlinkat_rights, td);
+ pathseg, path, dfd, &cap_unlinkat_rights, td);
if ((error = namei(&nd)) != 0)
- return (error);
+ goto fdout;
vp = nd.ni_vp;
if (vp->v_type != VDIR) {
error = ENOTDIR;
@@ -3742,6 +3792,12 @@
error = EBUSY;
goto out;
}
+
+ if (fp != NULL && fp->f_vnode != vp) {
+ error = EDEADLK;
+ goto out;
+ }
+
#ifdef MAC
error = mac_vnode_check_unlink(td->td_ucred, nd.ni_dvp, vp,
&nd.ni_cnd);
@@ -3756,7 +3812,7 @@
else
vput(nd.ni_dvp);
if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
- return (error);
+ goto fdout;
goto restart;
}
vfs_notify_upper(vp, VFS_NOTIFY_UPPER_UNLINK);
@@ -3769,6 +3825,9 @@
vrele(nd.ni_dvp);
else
vput(nd.ni_dvp);
+fdout:
+ if (fp != NULL)
+ fdrop(fp, td);
return (error);
}
Index: sys/sys/fcntl.h
===================================================================
--- sys/sys/fcntl.h
+++ sys/sys/fcntl.h
@@ -316,6 +316,16 @@
#define POSIX_FADV_NOREUSE 5 /* access data only once */
#endif
+
+#ifdef __BSD_VISIBLE
+/*
+ * Magic value that specify that corresponding file descriptor to filename
+ * is unknown and sanitary check should be omitted in the funlinkat() and
+ * similar syscalls.
+ */
+#define FD_NONE -200
+#endif
+
#ifndef _KERNEL
__BEGIN_DECLS
int open(const char *, int, ...);
Index: sys/sys/syscallsubr.h
===================================================================
--- sys/sys/syscallsubr.h
+++ sys/sys/syscallsubr.h
@@ -218,7 +218,7 @@
enum uio_seg fromseg, struct mbuf **controlp);
int kern_renameat(struct thread *td, int oldfd, const char *old, int newfd,
const char *new, enum uio_seg pathseg);
-int kern_rmdirat(struct thread *td, int fd, const char *path,
+int kern_frmdirat(struct thread *td, int dfd, const char *path, int fd,
enum uio_seg pathseg, int flag);
int kern_sched_getparam(struct thread *td, struct thread *targettd,
struct sched_param *param);
@@ -285,7 +285,7 @@
int kern_thr_suspend(struct thread *td, struct timespec *tsp);
int kern_truncate(struct thread *td, const char *path,
enum uio_seg pathseg, off_t length);
-int kern_unlinkat(struct thread *td, int fd, const char *path,
+int kern_funlinkat(struct thread *td, int dfd, const char *path, int fd,
enum uio_seg pathseg, int flag, ino_t oldinum);
int kern_utimesat(struct thread *td, int fd, const char *path,
enum uio_seg pathseg, struct timeval *tptr, enum uio_seg tptrseg);
Index: sys/ufs/ffs/ffs_alloc.c
===================================================================
--- sys/ufs/ffs/ffs_alloc.c
+++ sys/ufs/ffs/ffs_alloc.c
@@ -3409,14 +3409,15 @@
}
#endif /* DEBUG */
/*
- * kern_unlinkat will do its own start/finish writes and
+ * kern_funlinkat will do its own start/finish writes and
* they do not nest, so drop ours here. Setting mp == NULL
* indicates that vn_finished_write is not needed down below.
*/
vn_finished_write(mp);
mp = NULL;
- error = kern_unlinkat(td, AT_FDCWD, (char *)(intptr_t)cmd.value,
- UIO_USERSPACE, 0, (ino_t)cmd.size);
+ error = kern_funlinkat(td, AT_FDCWD,
+ (char *)(intptr_t)cmd.value, FD_NONE, UIO_USERSPACE,
+ 0, (ino_t)cmd.size);
break;
case FFS_SET_INODE:
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Oct 23, 7:24 AM (12 m, 17 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
24085759
Default Alt Text
D14567.id52946.diff (14 KB)
Attached To
Mode
D14567: Introduce funlinkat.
Attached
Detach File
Event Timeline
Log In to Comment