* Attempt to initiate a splice from pipe to file.
*/
static long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
- size_t len, unsigned int flags)
+ loff_t __user *off_out, size_t len,
+ unsigned int flags)
{
loff_t pos;
int ret;
if (!(out->f_mode & FMODE_WRITE))
return -EBADF;
+ if (off_out && copy_from_user(&out->f_pos, off_out, sizeof(loff_t)))
+ return -EFAULT;
+
pos = out->f_pos;
+
ret = rw_verify_area(WRITE, out, &pos, len);
if (unlikely(ret < 0))
return ret;
/*
* Attempt to initiate a splice from a file to a pipe.
*/
-static long do_splice_to(struct file *in, struct pipe_inode_info *pipe,
- size_t len, unsigned int flags)
+static long do_splice_to(struct file *in, loff_t __user *off_in,
+ struct pipe_inode_info *pipe, size_t len,
+ unsigned int flags)
{
loff_t pos, isize, left;
int ret;
if (!(in->f_mode & FMODE_READ))
return -EBADF;
+ if (off_in && copy_from_user(&in->f_pos, off_in, sizeof(loff_t)))
+ return -EFAULT;
+
pos = in->f_pos;
+
ret = rw_verify_area(READ, in, &pos, len);
if (unlikely(ret < 0))
return ret;
/*
* Determine where to splice to/from.
*/
-static long do_splice(struct file *in, struct file *out, size_t len,
- unsigned int flags)
+static long do_splice(struct file *in, loff_t __user *off_in,
+ struct file *out, loff_t __user *off_out,
+ size_t len, unsigned int flags)
{
struct pipe_inode_info *pipe;
+ if (off_out && out->f_op->llseek == no_llseek)
+ return -EINVAL;
+ if (off_in && in->f_op->llseek == no_llseek)
+ return -EINVAL;
+
pipe = in->f_dentry->d_inode->i_pipe;
- if (pipe)
- return do_splice_from(pipe, out, len, flags);
+ if (pipe) {
+ if (off_in)
+ return -ESPIPE;
+
+ return do_splice_from(pipe, out, off_out, len, flags);
+ }
pipe = out->f_dentry->d_inode->i_pipe;
- if (pipe)
- return do_splice_to(in, pipe, len, flags);
+ if (pipe) {
+ if (off_out)
+ return -ESPIPE;
+
+ return do_splice_to(in, off_in, pipe, len, flags);
+ }
return -EINVAL;
}
-asmlinkage long sys_splice(int fdin, int fdout, size_t len, unsigned int flags)
+asmlinkage long sys_splice(int fd_in, loff_t __user *off_in,
+ int fd_out, loff_t __user *off_out,
+ size_t len, unsigned int flags)
{
long error;
struct file *in, *out;
return 0;
error = -EBADF;
- in = fget_light(fdin, &fput_in);
+ in = fget_light(fd_in, &fput_in);
if (in) {
if (in->f_mode & FMODE_READ) {
- out = fget_light(fdout, &fput_out);
+ out = fget_light(fd_out, &fput_out);
if (out) {
if (out->f_mode & FMODE_WRITE)
- error = do_splice(in, out, len, flags);
+ error = do_splice(in, off_in,
+ out, off_out,
+ len, flags);
fput_light(out, fput_out);
}
}