diff options
author | pjd <pjd@FreeBSD.org> | 2013-03-21 22:59:01 +0000 |
---|---|---|
committer | pjd <pjd@FreeBSD.org> | 2013-03-21 22:59:01 +0000 |
commit | 635dbe90f28856681c546e79b162657930ba6248 (patch) | |
tree | c837bb52e4e3da9316dcdbedaadda8c664bf4f22 /sys/kern/vfs_syscalls.c | |
parent | 5fc1bac31561b1a789448e02dc042557d6fbbbdf (diff) | |
download | FreeBSD-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.c | 65 |
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); } |