summaryrefslogtreecommitdiffstats
path: root/sys/kern/vfs_syscalls.c
diff options
context:
space:
mode:
authorpjd <pjd@FreeBSD.org>2013-03-21 22:59:01 +0000
committerpjd <pjd@FreeBSD.org>2013-03-21 22:59:01 +0000
commit635dbe90f28856681c546e79b162657930ba6248 (patch)
treec837bb52e4e3da9316dcdbedaadda8c664bf4f22 /sys/kern/vfs_syscalls.c
parent5fc1bac31561b1a789448e02dc042557d6fbbbdf (diff)
downloadFreeBSD-src-635dbe90f28856681c546e79b162657930ba6248.zip
FreeBSD-src-635dbe90f28856681c546e79b162657930ba6248.tar.gz
Implement chflagsat(2) system call, similar to fchmodat(2), but operates on
file flags. Reviewed by: kib, jilles Sponsored by: The FreeBSD Foundation
Diffstat (limited to 'sys/kern/vfs_syscalls.c')
-rw-r--r--sys/kern/vfs_syscalls.c65
1 files changed, 50 insertions, 15 deletions
diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c
index 6195321..10e9c99 100644
--- a/sys/kern/vfs_syscalls.c
+++ b/sys/kern/vfs_syscalls.c
@@ -101,6 +101,10 @@ SDT_PROBE_ARGTYPE(vfs, , stat, reg, 1, "int");
static int chroot_refuse_vdir_fds(struct filedesc *fdp);
static int getutimes(const struct timeval *, enum uio_seg, struct timespec *);
+static int kern_chflags(struct thread *td, const char *path,
+ enum uio_seg pathseg, u_long flags);
+static int kern_chflagsat(struct thread *td, int fd, const char *path,
+ enum uio_seg pathseg, u_long flags, int atflag);
static int setfflags(struct thread *td, struct vnode *, u_long);
static int setutimes(struct thread *td, struct vnode *,
const struct timespec *, int, int);
@@ -2669,17 +2673,38 @@ sys_chflags(td, uap)
u_long flags;
} */ *uap;
{
- int error;
- struct nameidata nd;
- AUDIT_ARG_FFLAGS(uap->flags);
- NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNODE1, UIO_USERSPACE, uap->path, td);
- if ((error = namei(&nd)) != 0)
- return (error);
- NDFREE(&nd, NDF_ONLY_PNBUF);
- error = setfflags(td, nd.ni_vp, uap->flags);
- vrele(nd.ni_vp);
- return (error);
+ return (kern_chflags(td, uap->path, UIO_USERSPACE, uap->flags));
+}
+
+#ifndef _SYS_SYSPROTO_H_
+struct chflagsat_args {
+ int fd;
+ const char *path;
+ u_long flags;
+ int atflag;
+}
+#endif
+int
+sys_chflagsat(struct thread *td, struct chflagsat_args *uap)
+{
+ int fd = uap->fd;
+ char *path = uap->path;
+ u_long flags = uap->flags;
+ int atflag = uap->atflag;
+
+ if (atflag & ~AT_SYMLINK_NOFOLLOW)
+ return (EINVAL);
+
+ return (kern_chflagsat(td, fd, path, UIO_USERSPACE, flags, atflag));
+}
+
+static int
+kern_chflags(struct thread *td, const char *path, enum uio_seg pathseg,
+ u_long flags)
+{
+
+ return (kern_chflagsat(td, AT_FDCWD, path, pathseg, flags, 0));
}
/*
@@ -2693,16 +2718,26 @@ sys_lchflags(td, uap)
u_long flags;
} */ *uap;
{
- int error;
+
+ return (kern_chflagsat(td, AT_FDCWD, uap->path, UIO_USERSPACE,
+ uap->flags, AT_SYMLINK_NOFOLLOW));
+}
+
+static int
+kern_chflagsat(struct thread *td, int fd, const char *path,
+ enum uio_seg pathseg, u_long flags, int atflag)
+{
struct nameidata nd;
+ int error, follow;
- AUDIT_ARG_FFLAGS(uap->flags);
- NDINIT(&nd, LOOKUP, NOFOLLOW | AUDITVNODE1, UIO_USERSPACE, uap->path,
- td);
+ AUDIT_ARG_FFLAGS(flags);
+ follow = (atflag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : FOLLOW;
+ NDINIT_ATRIGHTS(&nd, LOOKUP, follow | AUDITVNODE1, pathseg, path, fd,
+ CAP_FCHFLAGS, td);
if ((error = namei(&nd)) != 0)
return (error);
NDFREE(&nd, NDF_ONLY_PNBUF);
- error = setfflags(td, nd.ni_vp, uap->flags);
+ error = setfflags(td, nd.ni_vp, flags);
vrele(nd.ni_vp);
return (error);
}
OpenPOWER on IntegriCloud