--- //depot/vendor/freebsd/src/sys/dev/streams/streams.c 2007/12/30 01:46:44 +++ //depot/user/rwatson/memfd/src/sys/dev/streams/streams.c 2008/01/06 05:28:47 @@ -90,6 +90,7 @@ static struct fileops svr4_netops = { .fo_read = soo_read, .fo_write = soo_write, + .fo_truncate = soo_truncate, .fo_ioctl = soo_ioctl, .fo_poll = soo_poll, .fo_kqfilter = soo_kqfilter, --- //depot/vendor/freebsd/src/sys/fs/devfs/devfs_vnops.c 2007/12/30 01:46:44 +++ //depot/user/rwatson/memfd/src/sys/fs/devfs/devfs_vnops.c 2008/01/06 05:28:47 @@ -1278,6 +1278,13 @@ return (devfs_allocv(de, ap->a_dvp->v_mount, ap->a_vpp, td)); } +static int +devfs_truncate_f(struct file *fp, off_t length, struct ucred *cred, struct thread *td) +{ + + return (vnops.fo_truncate(fp, length, cred, td)); +} + /* ARGSUSED */ static int devfs_write_f(struct file *fp, struct uio *uio, struct ucred *cred, int flags, struct thread *td) @@ -1322,6 +1329,7 @@ static struct fileops devfs_ops_f = { .fo_read = devfs_read_f, .fo_write = devfs_write_f, + .fo_truncate = devfs_truncate_f, .fo_ioctl = devfs_ioctl_f, .fo_poll = devfs_poll_f, .fo_kqfilter = devfs_kqfilter_f, --- //depot/vendor/freebsd/src/sys/fs/fifofs/fifo_vnops.c 2007/12/30 01:46:44 +++ //depot/user/rwatson/memfd/src/sys/fs/fifofs/fifo_vnops.c 2008/01/06 05:28:47 @@ -61,10 +61,12 @@ static fo_kqfilter_t fifo_kqfilter_f; static fo_stat_t fifo_stat_f; static fo_close_t fifo_close_f; +static fo_truncate_t fifo_truncate_f; struct fileops fifo_ops_f = { .fo_read = fifo_read_f, .fo_write = fifo_write_f, + .fo_truncate = fifo_truncate_f, .fo_ioctl = fifo_ioctl_f, .fo_poll = fifo_poll_f, .fo_kqfilter = fifo_kqfilter_f, @@ -724,6 +726,13 @@ } static int +fifo_truncate_f(struct file *fp, off_t length, struct ucred *cred, struct thread *td) +{ + + return (vnops.fo_truncate(fp, length, cred, td)); +} + +static int fifo_write_f(struct file *fp, struct uio *uio, struct ucred *cred, int flags, struct thread *td) { struct fifoinfo *fip; --- //depot/vendor/freebsd/src/sys/kern/kern_descrip.c 2007/12/30 01:46:44 +++ //depot/user/rwatson/memfd/src/sys/kern/kern_descrip.c 2008/01/06 05:28:47 @@ -2759,6 +2761,13 @@ } static int +badfo_truncate(struct file *fp, off_t length, struct ucred *active_cred, struct thread *td) +{ + + return (EINVAL); +} + +static int badfo_ioctl(struct file *fp, u_long com, void *data, struct ucred *active_cred, struct thread *td) { @@ -2796,6 +2805,7 @@ struct fileops badfileops = { .fo_read = badfo_readwrite, .fo_write = badfo_readwrite, + .fo_truncate = badfo_truncate, .fo_ioctl = badfo_ioctl, .fo_poll = badfo_poll, .fo_kqfilter = badfo_kqfilter, --- //depot/vendor/freebsd/src/sys/kern/kern_event.c 2007/12/30 01:46:44 +++ //depot/user/rwatson/memfd/src/sys/kern/kern_event.c 2008/01/06 05:28:47 @@ -105,6 +105,7 @@ static fo_rdwr_t kqueue_read; static fo_rdwr_t kqueue_write; +static fo_truncate_t kqueue_truncate; static fo_ioctl_t kqueue_ioctl; static fo_poll_t kqueue_poll; static fo_kqfilter_t kqueue_kqfilter; @@ -114,6 +115,7 @@ static struct fileops kqueueops = { .fo_read = kqueue_read, .fo_write = kqueue_write, + .fo_truncate = kqueue_truncate, .fo_ioctl = kqueue_ioctl, .fo_poll = kqueue_poll, .fo_kqfilter = kqueue_kqfilter, @@ -1324,6 +1326,15 @@ /*ARGSUSED*/ static int +kqueue_truncate(struct file *fp, off_t length, struct ucred *active_cred, + struct thread *td) +{ + + return (EINVAL); +} + +/*ARGSUSED*/ +static int kqueue_ioctl(struct file *fp, u_long cmd, void *data, struct ucred *active_cred, struct thread *td) { --- //depot/vendor/freebsd/src/sys/kern/sys_generic.c 2007/12/30 01:46:44 +++ //depot/user/rwatson/memfd/src/sys/kern/sys_generic.c 2008/01/06 05:28:47 @@ -52,6 +52,7 @@ #include #include #include +#include #include #include #include @@ -69,7 +70,7 @@ #include #endif -#include +#include static MALLOC_DEFINE(M_IOCTLOPS, "ioctlops", "ioctl data buffer"); static MALLOC_DEFINE(M_SELECT, "select", "select() buffer"); @@ -544,6 +545,70 @@ return (error); } +/* + * Truncate a file given a file descriptor. + * + * Can't use fget_write() here, since must return EINVAL and not EBADF if the + * descriptor isn't writable. + */ +int +kern_ftruncate(td, fd, length) + struct thread *td; + int fd; + off_t length; +{ + struct file *fp; + int error; + + AUDIT_ARG(fd, fd); + if (length < 0) + return (EINVAL); + error = fget(td, fd, &fp); + if (error) + return (error); + AUDIT_ARG(file, td->td_proc, fp); + if (!(fp->f_flag & FWRITE)) { + fdrop(fp, td); + return (EINVAL); + } + error = fo_truncate(fp, length, td->td_ucred, td); + fdrop(fp, td); + return (error); +} + +#ifndef _SYS_SYSPROTO_H_ +struct ftruncate_args { + int fd; + int pad; + off_t length; +}; +#endif +int +ftruncate(td, uap) + struct thread *td; + struct ftruncate_args *uap; +{ + + return (kern_ftruncate(td, uap->fd, uap->length)); +} + +#if defined(COMPAT_43) +#ifndef _SYS_SYSPROTO_H_ +struct oftruncate_args { + int fd; + long length; +}; +#endif +int +oftruncate(td, uap) + struct thread *td; + struct oftruncate_args *uap; +{ + + return (kern_ftruncate(td, uap->fd, uap->length)); +} +#endif /* COMPAT_43 */ + #ifndef _SYS_SYSPROTO_H_ struct ioctl_args { int fd; --- //depot/vendor/freebsd/src/sys/kern/sys_pipe.c 2007/12/30 01:46:44 +++ //depot/user/rwatson/memfd/src/sys/kern/sys_pipe.c 2008/01/06 05:28:47 @@ -140,6 +140,7 @@ */ static fo_rdwr_t pipe_read; static fo_rdwr_t pipe_write; +static fo_truncate_t pipe_truncate; static fo_ioctl_t pipe_ioctl; static fo_poll_t pipe_poll; static fo_kqfilter_t pipe_kqfilter; @@ -149,6 +150,7 @@ static struct fileops pipeops = { .fo_read = pipe_read, .fo_write = pipe_write, + .fo_truncate = pipe_truncate, .fo_ioctl = pipe_ioctl, .fo_poll = pipe_poll, .fo_kqfilter = pipe_kqfilter, @@ -1230,6 +1232,18 @@ return (error); } +/* ARGSUSED */ +static int +pipe_truncate(fp, length, active_cred, td) + struct file *fp; + off_t length; + struct ucred *active_cred; + struct thread *td; +{ + + return (EINVAL); +} + /* * we implement a very minimal set of ioctls for compatibility with sockets. */ --- //depot/vendor/freebsd/src/sys/kern/sys_socket.c 2007/10/24 19:06:35 +++ //depot/user/rwatson/memfd/src/sys/kern/sys_socket.c 2008/01/06 05:28:47 @@ -59,6 +59,7 @@ struct fileops socketops = { .fo_read = soo_read, .fo_write = soo_write, + .fo_truncate = soo_truncate, .fo_ioctl = soo_ioctl, .fo_poll = soo_poll, .fo_kqfilter = soo_kqfilter, @@ -110,6 +111,14 @@ } int +soo_truncate(struct file *fp, off_t length, struct ucred *active_cred, + struct thread *td) +{ + + return (EINVAL); +} + +int soo_ioctl(struct file *fp, u_long cmd, void *data, struct ucred *active_cred, struct thread *td) { --- //depot/vendor/freebsd/src/sys/kern/uipc_mqueue.c 2007/12/30 01:46:44 +++ //depot/user/rwatson/memfd/src/sys/kern/uipc_mqueue.c 2008/01/06 05:28:47 @@ -2317,6 +2317,14 @@ } static int +mqf_truncate(struct file *fp, off_t length, struct ucred *active_cred, + struct thread *td) +{ + + return (EINVAL); +} + +static int mqf_ioctl(struct file *fp, u_long cmd, void *data, struct ucred *active_cred, struct thread *td) { @@ -2433,6 +2441,7 @@ static struct fileops mqueueops = { .fo_read = mqf_read, .fo_write = mqf_write, + .fo_truncate = mqf_truncate, .fo_ioctl = mqf_ioctl, .fo_poll = mqf_poll, .fo_kqfilter = mqf_kqfilter, --- //depot/vendor/freebsd/src/sys/kern/vfs_syscalls.c 2007/12/30 01:46:44 +++ //depot/user/rwatson/memfd/src/sys/kern/vfs_syscalls.c 2007/12/31 22:01:59 @@ -3086,68 +3086,6 @@ return (error); } -/* - * Truncate a file given a file descriptor. - */ -#ifndef _SYS_SYSPROTO_H_ -struct ftruncate_args { - int fd; - int pad; - off_t length; -}; -#endif -int -ftruncate(td, uap) - struct thread *td; - register struct ftruncate_args /* { - int fd; - int pad; - off_t length; - } */ *uap; -{ - struct mount *mp; - struct vattr vattr; - struct vnode *vp; - struct file *fp; - int vfslocked; - int error; - - AUDIT_ARG(fd, uap->fd); - if (uap->length < 0) - return(EINVAL); - if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0) - return (error); - if ((fp->f_flag & FWRITE) == 0) { - fdrop(fp, td); - return (EINVAL); - } - vp = fp->f_vnode; - vfslocked = VFS_LOCK_GIANT(vp->v_mount); - if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) - goto drop; - VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE); - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); - AUDIT_ARG(vnode, vp, ARG_VNODE1); - if (vp->v_type == VDIR) - error = EISDIR; -#ifdef MAC - else if ((error = mac_vnode_check_write(td->td_ucred, fp->f_cred, - vp))) { - } -#endif - else if ((error = vn_writechk(vp)) == 0) { - VATTR_NULL(&vattr); - vattr.va_size = uap->length; - error = VOP_SETATTR(vp, &vattr, fp->f_cred, td); - } - VOP_UNLOCK(vp, 0, td); - vn_finished_write(mp); -drop: - VFS_UNLOCK_GIANT(vfslocked); - fdrop(fp, td); - return (error); -} - #if defined(COMPAT_43) /* * Truncate a file given its path name. @@ -3176,34 +3114,6 @@ nuap.length = uap->length; return (truncate(td, &nuap)); } - -/* - * Truncate a file given a file descriptor. - */ -#ifndef _SYS_SYSPROTO_H_ -struct oftruncate_args { - int fd; - long length; -}; -#endif -int -oftruncate(td, uap) - struct thread *td; - register struct oftruncate_args /* { - int fd; - long length; - } */ *uap; -{ - struct ftruncate_args /* { - int fd; - int pad; - off_t length; - } */ nuap; - - nuap.fd = uap->fd; - nuap.length = uap->length; - return (ftruncate(td, &nuap)); -} #endif /* COMPAT_43 */ /* Versions with the pad argument */ --- //depot/vendor/freebsd/src/sys/kern/vfs_vnops.c 2007/12/30 01:46:44 +++ //depot/user/rwatson/memfd/src/sys/kern/vfs_vnops.c 2008/01/06 05:28:47 @@ -66,6 +66,7 @@ static fo_rdwr_t vn_read; static fo_rdwr_t vn_write; +static fo_truncate_t vn_truncate; static fo_ioctl_t vn_ioctl; static fo_poll_t vn_poll; static fo_kqfilter_t vn_kqfilter; @@ -75,6 +76,7 @@ struct fileops vnops = { .fo_read = vn_read, .fo_write = vn_write, + .fo_truncate = vn_truncate, .fo_ioctl = vn_ioctl, .fo_poll = vn_poll, .fo_kqfilter = vn_kqfilter, @@ -600,6 +602,53 @@ } /* + * File table truncate routine. + */ +static int +vn_truncate(fp, length, active_cred, td) + struct file *fp; + off_t length; + struct ucred *active_cred; + struct thread *td; +{ + struct vattr vattr; + struct mount *mp; + struct vnode *vp; + int vfslocked; + int error; + + vp = fp->f_vnode; + vfslocked = VFS_LOCK_GIANT(vp->v_mount); + error = vn_start_write(vp, &mp, V_WAIT | PCATCH); + if (error) { + VFS_UNLOCK_GIANT(vfslocked); + return (error); + } + VOP_LEASE(vp, td, active_cred, LEASE_WRITE); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); + if (vp->v_type == VDIR) { + error = EISDIR; + goto out; + } +#ifdef MAC + error = mac_vnode_check_write(active_cred, fp->f_cred, vp); + if (error) + goto out; +#endif + error = vn_writechk(vp); + if (error == 0) { + VATTR_NULL(&vattr); + vattr.va_size = length; + error = VOP_SETATTR(vp, &vattr, fp->f_cred, td); + } +out: + VOP_UNLOCK(vp, 0, td); + vn_finished_write(mp); + VFS_UNLOCK_GIANT(vfslocked); + return (error); +} + +/* * File table vnode stat routine. */ static int --- //depot/vendor/freebsd/src/sys/opencrypto/cryptodev.c 2007/12/30 01:46:44 +++ //depot/user/rwatson/memfd/src/sys/opencrypto/cryptodev.c 2008/01/06 05:28:47 @@ -86,6 +86,8 @@ static int cryptof_rw(struct file *fp, struct uio *uio, struct ucred *cred, int flags, struct thread *); +static int cryptof_truncate(struct file *, off_t, struct ucred *, + struct thread *); static int cryptof_ioctl(struct file *, u_long, void *, struct ucred *, struct thread *); static int cryptof_poll(struct file *, int, struct ucred *, struct thread *); @@ -97,6 +99,7 @@ static struct fileops cryptofops = { .fo_read = cryptof_rw, .fo_write = cryptof_rw, + .fo_truncate = cryptof_truncate, .fo_ioctl = cryptof_ioctl, .fo_poll = cryptof_poll, .fo_kqfilter = cryptof_kqfilter, @@ -129,6 +132,17 @@ return (EIO); } +static int +cryptof_truncate( + struct file *fp, + off_t length, + struct ucred *active_cred, + struct thread *td) +{ + + return (EINVAL); +} + /* * Check a crypto identifier to see if it requested * a software device/driver. This can be done either --- //depot/vendor/freebsd/src/sys/sys/file.h 2007/12/30 01:46:44 +++ //depot/user/rwatson/memfd/src/sys/sys/file.h 2008/01/06 05:28:47 @@ -69,6 +70,8 @@ struct ucred *active_cred, int flags, struct thread *td); #define FOF_OFFSET 1 /* Use the offset in uio argument */ +typedef int fo_truncate_t(struct file *fp, off_t length, + struct ucred *active_cred, struct thread *td); typedef int fo_ioctl_t(struct file *fp, u_long com, void *data, struct ucred *active_cred, struct thread *td); typedef int fo_poll_t(struct file *fp, int events, @@ -82,6 +85,7 @@ struct fileops { fo_rdwr_t *fo_read; fo_rdwr_t *fo_write; + fo_truncate_t *fo_truncate; fo_ioctl_t *fo_ioctl; fo_poll_t *fo_poll; fo_kqfilter_t *fo_kqfilter; @@ -175,6 +179,7 @@ */ fo_rdwr_t soo_read; fo_rdwr_t soo_write; +fo_truncate_t soo_truncate; fo_ioctl_t soo_ioctl; fo_poll_t soo_poll; fo_kqfilter_t soo_kqfilter; @@ -195,6 +200,7 @@ static __inline fo_rdwr_t fo_read; static __inline fo_rdwr_t fo_write; +static __inline fo_truncate_t fo_truncate; static __inline fo_ioctl_t fo_ioctl; static __inline fo_poll_t fo_poll; static __inline fo_kqfilter_t fo_kqfilter; @@ -226,6 +232,17 @@ } static __inline int +fo_truncate(fp, length, active_cred, td) + struct file *fp; + off_t length; + struct ucred *active_cred; + struct thread *td; +{ + + return ((*fp->f_ops->fo_truncate)(fp, length, active_cred, td)); +} + +static __inline int fo_ioctl(fp, com, data, active_cred, td) struct file *fp; u_long com; --- //depot/vendor/freebsd/src/sys/sys/syscallsubr.h 2007/06/07 19:51:00 +++ //depot/user/rwatson/memfd/src/sys/sys/syscallsubr.h 2007/10/15 21:00:14 @@ -82,6 +82,7 @@ int kern_fhstatfs(struct thread *td, fhandle_t fh, struct statfs *buf); int kern_fstat(struct thread *td, int fd, struct stat *sbp); int kern_fstatfs(struct thread *td, int fd, struct statfs *buf); +int kern_ftruncate(struct thread *td, int fd, off_t length); int kern_futimes(struct thread *td, int fd, struct timeval *tptr, enum uio_seg tptrseg); int kern_getfsstat(struct thread *td, struct statfs **buf, size_t bufsize,