| 4781 | } |
| 4782 | |
| 4783 | int |
| 4784 | kern_copy_file_range(struct thread *td, int infd, off_t *inoffp, int outfd, |
| 4785 | off_t *outoffp, size_t len, unsigned int flags) |
| 4786 | { |
| 4787 | struct file *infp, *outfp; |
| 4788 | struct vnode *invp, *outvp; |
| 4789 | int error; |
| 4790 | size_t retlen; |
| 4791 | void *rl_rcookie, *rl_wcookie; |
| 4792 | off_t savinoff, savoutoff; |
| 4793 | |
| 4794 | infp = outfp = NULL; |
| 4795 | rl_rcookie = rl_wcookie = NULL; |
| 4796 | savinoff = -1; |
| 4797 | error = 0; |
| 4798 | retlen = 0; |
| 4799 | |
| 4800 | if (flags != 0) { |
| 4801 | error = EINVAL; |
| 4802 | goto out; |
| 4803 | } |
| 4804 | if (len > SSIZE_MAX) |
| 4805 | /* |
| 4806 | * Although the len argument is size_t, the return argument |
| 4807 | * is ssize_t (which is signed). Therefore a size that won't |
| 4808 | * fit in ssize_t can't be returned. |
| 4809 | */ |
| 4810 | len = SSIZE_MAX; |
| 4811 | |
| 4812 | /* Get the file structures for the file descriptors. */ |
| 4813 | error = fget_read(td, infd, &cap_read_rights, &infp); |
| 4814 | if (error != 0) |
| 4815 | goto out; |
| 4816 | if (infp->f_ops == &badfileops) { |
| 4817 | error = EBADF; |
| 4818 | goto out; |
| 4819 | } |
| 4820 | if (infp->f_vnode == NULL) { |
| 4821 | error = EINVAL; |
| 4822 | goto out; |
| 4823 | } |
| 4824 | error = fget_write(td, outfd, &cap_write_rights, &outfp); |
| 4825 | if (error != 0) |
| 4826 | goto out; |
| 4827 | if (outfp->f_ops == &badfileops) { |
| 4828 | error = EBADF; |
| 4829 | goto out; |
| 4830 | } |
| 4831 | if (outfp->f_vnode == NULL) { |
| 4832 | error = EINVAL; |
| 4833 | goto out; |
| 4834 | } |
| 4835 | |
| 4836 | /* Set the offset pointers to the correct place. */ |
| 4837 | if (inoffp == NULL) |
| 4838 | inoffp = &infp->f_offset; |
| 4839 | if (outoffp == NULL) |
| 4840 | outoffp = &outfp->f_offset; |
no test coverage detected