Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F115758835
D14567.id43620.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
15 KB
Referenced Files
None
Subscribers
None
D14567.id43620.diff
View Options
Index: include/unistd.h
===================================================================
--- include/unistd.h
+++ include/unistd.h
@@ -583,6 +583,7 @@
int undelete(const char *);
int unwhiteout(const char *);
void *valloc(size_t); /* obsoleted by malloc() */
+int fdunlinkat(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
@@ -478,6 +478,7 @@
MLINKS+=thr_kill.2 thr_kill2.2
MLINKS+=truncate.2 ftruncate.2
MLINKS+=unlink.2 unlinkat.2
+MLINKS+=unlink.2 fdunlinkat.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
@@ -400,6 +400,7 @@
statfs;
cpuset_getdomain;
cpuset_setdomain;
+ fdunlinkat;
};
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 December 1, 2017
+.Dd June 10, 2018
.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 fdunlinkat "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
@@ -105,6 +107,26 @@
respectively, depending on whether or not the
.Dv AT_REMOVEDIR
bit is set in flag.
+.Pp
+The
+.Fn fdunlinkat
+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 fdunlinkat
+behaves exactly like
+.Fn unlinkat .
.Sh RETURN VALUES
.Rv -std unlink
.Sh ERRORS
@@ -201,6 +223,15 @@
.Dv AT_FDCWD
nor a file descriptor associated with a directory.
.El
+.Pp
+In addition to the errors returned by the
+.Fn unlinkat ,
+.Fn fdunlinkat
+may fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The file descriptor is not associated with the path.
+.El
.Sh SEE ALSO
.Xr chflags 2 ,
.Xr close 2 ,
@@ -220,6 +251,10 @@
.Fn unlinkat
system call appeared in
.Fx 8.0 .
+The
+.Fn fdunlinkat
+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,7 @@
ASSERT(seg == UIO_SYSSPACE);
ASSERT(dirflag == RMFILE);
- return (kern_unlinkat(curthread, AT_FDCWD, fnamep, seg, 0));
+ return (kern_fdunlinkat(curthread, AT_FDCWD, fnamep, FD_NONE, seg, 0));
}
#endif /* _KERNEL */
Index: sys/compat/cloudabi/cloudabi_file.c
===================================================================
--- sys/compat/cloudabi/cloudabi_file.c
+++ sys/compat/cloudabi/cloudabi_file.c
@@ -750,9 +750,11 @@
return (error);
if (uap->flags & CLOUDABI_UNLINK_REMOVEDIR)
- error = kern_rmdirat(td, uap->fd, path, UIO_SYSSPACE);
+ error = kern_fdrmdirat(td, uap->fd, path, FD_NONE,
+ UIO_SYSSPACE);
else
- error = kern_unlinkat(td, uap->fd, path, UIO_SYSSPACE, 0);
+ error = kern_fdunlinkat(td, uap->fd, path, FD_NONE,
+ UIO_SYSSPACE, 0);
cloudabi_freestr(path);
return (error);
}
Index: sys/compat/freebsd32/capabilities.conf
===================================================================
--- sys/compat/freebsd32/capabilities.conf
+++ sys/compat/freebsd32/capabilities.conf
@@ -192,6 +192,7 @@
renameat
symlinkat
unlinkat
+fdunlinkat
freebsd32_utimensat
pdfork
pdgetpid
Index: sys/compat/freebsd32/syscalls.master
===================================================================
--- sys/compat/freebsd32/syscalls.master
+++ sys/compat/freebsd32/syscalls.master
@@ -1123,5 +1123,7 @@
cpuwhich_t which, uint32_t id1, uint32_t id2, \
size_t domainsetsize, domainset_t *mask, \
int policy); }
+563 AUE_UNLINKAT NOPROTO { int fdunlinkat(int dfd, const char *path, int fd, \
+ int flag, mode_t mode); }
; vim: syntax=off
Index: sys/compat/linux/linux_file.c
===================================================================
--- sys/compat/linux/linux_file.c
+++ sys/compat/linux/linux_file.c
@@ -580,7 +580,7 @@
printf(ARGS(unlink, "%s"), path);
#endif
- error = kern_unlinkat(td, AT_FDCWD, path, UIO_SYSSPACE, 0);
+ error = kern_fdunlinkat(td, AT_FDCWD, path, FD_NONE, UIO_SYSSPACE, 0);
if (error == EPERM) {
/* Introduce POSIX noncompliant behaviour of Linux */
if (kern_statat(td, 0, AT_FDCWD, path, UIO_SYSSPACE, &st,
@@ -612,9 +612,9 @@
#endif
if (args->flag & LINUX_AT_REMOVEDIR)
- error = kern_rmdirat(td, dfd, path, UIO_SYSSPACE);
+ error = kern_fdrmdirat(td, dfd, path, FD_NONE, UIO_SYSSPACE);
else
- error = kern_unlinkat(td, dfd, path, UIO_SYSSPACE, 0);
+ error = kern_fdunlinkat(td, dfd, path, FD_NONE, UIO_SYSSPACE, 0);
if (error == EPERM && !(args->flag & LINUX_AT_REMOVEDIR)) {
/* Introduce POSIX noncompliant behaviour of Linux */
if (kern_statat(td, AT_SYMLINK_NOFOLLOW, dfd, path,
@@ -725,7 +725,7 @@
if (ldebug(rmdir))
printf(ARGS(rmdir, "%s"), path);
#endif
- error = kern_rmdirat(td, AT_FDCWD, path, UIO_SYSSPACE);
+ error = kern_fdrmdirat(td, AT_FDCWD, path, FD_NONE, UIO_SYSSPACE);
LFREEPATH(path);
return (error);
}
Index: sys/i386/ibcs2/ibcs2_misc.c
===================================================================
--- sys/i386/ibcs2/ibcs2_misc.c
+++ sys/i386/ibcs2/ibcs2_misc.c
@@ -1071,7 +1071,7 @@
int error;
CHECKALTEXIST(td, uap->path, &path);
- error = kern_unlinkat(td, AT_FDCWD, path, UIO_SYSSPACE, 0);
+ error = kern_fdunlinkat(td, AT_FDCWD, path, FD_NONE, UIO_SYSSPACE, 0);
free(path, M_TEMP);
return (error);
}
@@ -1120,7 +1120,7 @@
int error;
CHECKALTEXIST(td, uap->path, &path);
- error = kern_rmdirat(td, AT_FDCWD, path, UIO_SYSSPACE);
+ error = kern_fdrmdirat(td, AT_FDCWD, path, FD_NONE, UIO_SYSSPACE);
free(path, M_TEMP);
return (error);
}
Index: sys/kern/capabilities.conf
===================================================================
--- sys/kern/capabilities.conf
+++ sys/kern/capabilities.conf
@@ -463,6 +463,7 @@
renameat
symlinkat
unlinkat
+fdunlinkat
utimensat
##
Index: sys/kern/syscalls.master
===================================================================
--- sys/kern/syscalls.master
+++ sys/kern/syscalls.master
@@ -1027,6 +1027,8 @@
cpuwhich_t which, id_t id, \
size_t domainsetsize, domainset_t *mask, \
int policy); }
+563 AUE_UNLINKAT STD { int fdunlinkat(int dfd, const char *path, int fd, \
+ int flag, mode_t mode); }
; 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
@@ -388,7 +388,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_fdunlinkat(td, AT_FDCWD, "/dev/dev", FD_NONE,
UIO_SYSSPACE, 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
@@ -1737,7 +1737,22 @@
sys_unlink(struct thread *td, struct unlink_args *uap)
{
- return (kern_unlinkat(td, AT_FDCWD, uap->path, UIO_USERSPACE, 0));
+ return (kern_fdunlinkat(td, AT_FDCWD, uap->path, FD_NONE, UIO_USERSPACE,
+ 0));
+}
+
+static int
+kern_fdunlinkat_ex(struct thread *td, int dfd, const char *path, int fd,
+ int flag, enum uio_seg pathseg, ino_t oldinum)
+{
+
+ if (flag & ~AT_REMOVEDIR)
+ return (EINVAL);
+
+ if (flag & AT_REMOVEDIR)
+ return (kern_fdrmdirat(td, dfd, path, fd, UIO_USERSPACE));
+
+ return (kern_fdunlinkat(td, dfd, path, fd, UIO_USERSPACE, 0));
}
#ifndef _SYS_SYSPROTO_H_
@@ -1750,43 +1765,65 @@
int
sys_unlinkat(struct thread *td, struct unlinkat_args *uap)
{
- int flag = uap->flag;
- int fd = uap->fd;
- char *path = uap->path;
- if (flag & ~AT_REMOVEDIR)
- return (EINVAL);
+ return (kern_fdunlinkat_ex(td, uap->fd, uap->path, FD_NONE, uap->flag,
+ UIO_USERSPACE, 0));
+}
- if (flag & AT_REMOVEDIR)
- return (kern_rmdirat(td, fd, path, UIO_USERSPACE));
- else
- return (kern_unlinkat(td, fd, path, UIO_USERSPACE, 0));
+#ifndef _SYS_SYSPROTO_H_
+struct fdunlinkat_args {
+ int dfd;
+ const char *path;
+ int fd;
+ int flag;
+};
+#endif
+int
+sys_fdunlinkat(struct thread *td, struct fdunlinkat_args *uap)
+{
+
+ return (kern_fdunlinkat_ex(td, uap->dfd, uap->path, uap->fd, uap->flag,
+ UIO_USERSPACE, 0));
}
int
-kern_unlinkat(struct thread *td, int fd, char *path, enum uio_seg pathseg,
- ino_t oldinum)
+kern_fdunlinkat(struct thread *td, int dfd, const char *path, int fd,
+ enum uio_seg pathseg, 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,
- pathseg, path, fd, cap_rights_init(&rights, CAP_UNLINKAT), td);
- if ((error = namei(&nd)) != 0)
- return (error == EINVAL ? EPERM : error);
+ pathseg, path, dfd, cap_rights_init(&rights, CAP_UNLINKAT), 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 = EINVAL;
} else {
/*
* The root of a mounted filesystem cannot be deleted.
@@ -1805,8 +1842,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
@@ -1828,6 +1866,9 @@
vrele(vp);
else
vput(vp);
+fdout:
+ if (fp != NULL)
+ fdrop(fp, td);
return (error);
}
@@ -2645,7 +2686,7 @@
AUDIT_ARG_FD(uap->fd);
AUDIT_ARG_FFLAGS(uap->flags);
- error = getvnode(td, uap->fd, cap_rights_init(&rights, CAP_FCHFLAGS),
+ error = getvnode(td, uap->fd, cap_rights_init(&rights, CAP_LOOKUP),
&fp);
if (error != 0)
return (error);
@@ -3675,24 +3716,35 @@
sys_rmdir(struct thread *td, struct rmdir_args *uap)
{
- return (kern_rmdirat(td, AT_FDCWD, uap->path, UIO_USERSPACE));
+ return (kern_fdrmdirat(td, AT_FDCWD, uap->path, FD_NONE,
+ UIO_USERSPACE));
}
int
-kern_rmdirat(struct thread *td, int fd, char *path, enum uio_seg pathseg)
+kern_fdrmdirat(struct thread *td, int dfd, const char *path, int fd,
+ enum uio_seg pathseg)
{
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,
- pathseg, path, fd, cap_rights_init(&rights, CAP_UNLINKAT), td);
+ pathseg, path, dfd, cap_rights_init(&rights, CAP_UNLINKAT), td);
if ((error = namei(&nd)) != 0)
- return (error);
+ goto fdout;
vp = nd.ni_vp;
if (vp->v_type != VDIR) {
error = ENOTDIR;
@@ -3712,6 +3764,12 @@
error = EBUSY;
goto out;
}
+
+ if (fp != NULL && fp->f_vnode != vp) {
+ error = EINVAL;
+ goto out;
+ }
+
#ifdef MAC
error = mac_vnode_check_unlink(td->td_ucred, nd.ni_dvp, vp,
&nd.ni_cnd);
@@ -3726,7 +3784,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);
@@ -3739,6 +3797,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
@@ -313,6 +313,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 fdunlinkat() and
+ * similar syscalls.
+ */
+#define FD_NONE -100
+#endif
+
#ifndef _KERNEL
__BEGIN_DECLS
int open(const char *, int, ...);
Index: sys/sys/syscallsubr.h
===================================================================
--- sys/sys/syscallsubr.h
+++ sys/sys/syscallsubr.h
@@ -216,7 +216,7 @@
enum uio_seg fromseg, struct mbuf **controlp);
int kern_renameat(struct thread *td, int oldfd, char *old, int newfd,
char *new, enum uio_seg pathseg);
-int kern_rmdirat(struct thread *td, int fd, char *path,
+int kern_fdrmdirat(struct thread *td, int dfd, const char *path, int fd,
enum uio_seg pathseg);
int kern_sched_getparam(struct thread *td, struct thread *targettd,
struct sched_param *param);
@@ -283,7 +283,7 @@
int kern_thr_suspend(struct thread *td, struct timespec *tsp);
int kern_truncate(struct thread *td, char *path, enum uio_seg pathseg,
off_t length);
-int kern_unlinkat(struct thread *td, int fd, char *path,
+int kern_fdunlinkat(struct thread *td, int dfd, const char *path, int fd,
enum uio_seg pathseg, ino_t oldinum);
int kern_utimesat(struct thread *td, int fd, 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
@@ -3096,14 +3096,15 @@
}
#endif /* DEBUG */
/*
- * kern_unlinkat will do its own start/finish writes and
+ * kern_fdunlinkat 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, (ino_t)cmd.size);
+ error = kern_fdunlinkat(td, AT_FDCWD,
+ (char *)(intptr_t)cmd.value, FD_NONE, UIO_USERSPACE,
+ (ino_t)cmd.size);
break;
case FFS_SET_INODE:
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Tue, Apr 29, 6:22 AM (2 h, 47 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
17837640
Default Alt Text
D14567.id43620.diff (15 KB)
Attached To
Mode
D14567: Introduce funlinkat.
Attached
Detach File
Event Timeline
Log In to Comment