summaryrefslogtreecommitdiffhomepage
path: root/pkg/sentry/syscalls/linux/sys_splice.go
diff options
context:
space:
mode:
authorNicolas Lacasse <nlacasse@google.com>2018-08-14 11:49:42 -0700
committerShentubot <shentubot@google.com>2018-08-14 11:50:49 -0700
commit6cf22781673d75cca459fd668cf291b387d52e0d (patch)
treedb11852c91ada5162d7d5fddf58d91f2d90591c8 /pkg/sentry/syscalls/linux/sys_splice.go
parent49031378d37db8990806851e02fcea8c52a8054c (diff)
Automated rollback of changelist 208284483
PiperOrigin-RevId: 208685417 Change-Id: Ie2849c4811e3a2d14a002f521cef018ded0c6c4a
Diffstat (limited to 'pkg/sentry/syscalls/linux/sys_splice.go')
-rw-r--r--pkg/sentry/syscalls/linux/sys_splice.go260
1 files changed, 0 insertions, 260 deletions
diff --git a/pkg/sentry/syscalls/linux/sys_splice.go b/pkg/sentry/syscalls/linux/sys_splice.go
deleted file mode 100644
index 8151e3599..000000000
--- a/pkg/sentry/syscalls/linux/sys_splice.go
+++ /dev/null
@@ -1,260 +0,0 @@
-// Copyright 2018 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package linux
-
-import (
- "io"
-
- "gvisor.googlesource.com/gvisor/pkg/abi/linux"
- "gvisor.googlesource.com/gvisor/pkg/sentry/arch"
- "gvisor.googlesource.com/gvisor/pkg/sentry/fs"
- "gvisor.googlesource.com/gvisor/pkg/sentry/kernel"
- "gvisor.googlesource.com/gvisor/pkg/sentry/kernel/kdefs"
- "gvisor.googlesource.com/gvisor/pkg/sentry/kernel/pipe"
- "gvisor.googlesource.com/gvisor/pkg/syserror"
-)
-
-// Splice implements linux syscall splice(2).
-func Splice(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
- fdIn := kdefs.FD(args[0].Int())
- offIn := args[1].Pointer()
- fdOut := kdefs.FD(args[2].Int())
- offOut := args[3].Pointer()
- size := int64(args[4].SizeT())
- flags := uint(args[5].Uint())
-
- fileIn := t.FDMap().GetFile(fdIn)
- if fileIn == nil {
- return 0, nil, syserror.EBADF
- }
- defer fileIn.DecRef()
- fileOut := t.FDMap().GetFile(fdOut)
- if fileOut == nil {
- return 0, nil, syserror.EBADF
- }
- defer fileOut.DecRef()
-
- // Check for whether we have pipes.
- ipipe := fs.IsPipe(fileIn.Dirent.Inode.StableAttr)
- opipe := fs.IsPipe(fileOut.Dirent.Inode.StableAttr)
- if (ipipe && offIn != 0) || (opipe && offOut != 0) {
- return 0, nil, syserror.ESPIPE
- }
-
- // Check if both file descriptors are pipes.
- if ipipe && opipe {
- var readPipe *pipe.Pipe
- switch p := fileIn.FileOperations.(type) {
- case *pipe.Reader:
- readPipe = p.ReaderWriter.Pipe
- case *pipe.ReaderWriter:
- readPipe = p.Pipe
- default:
- return 0, nil, syserror.EBADF
- }
- var writePipe *pipe.Pipe
- switch p := fileOut.FileOperations.(type) {
- case *pipe.Writer:
- writePipe = p.ReaderWriter.Pipe
- case *pipe.ReaderWriter:
- writePipe = p.Pipe
- default:
- return 0, nil, syserror.EBADF
- }
-
- // Splicing with two ends of the same pipe is not allowed.
- if readPipe == writePipe {
- return 0, nil, syserror.EINVAL
- }
- spliced, err := splicePipeToPipe(t, fileIn, fileOut, size, flags)
- if err != nil {
- return 0, nil, err
- }
- return uintptr(spliced), nil, nil
- }
-
- // Check if the file descriptor that contains the data to move is a pipe.
- if ipipe {
- flagsOut := fileOut.Flags()
- offset := uint64(fileOut.Offset())
-
- // If there is an offset for the file, ensure the file has the Pwrite flag.
- if offOut != 0 {
- if !flagsOut.Pwrite {
- return 0, nil, syserror.EINVAL
- }
- if _, err := t.CopyIn(offOut, &offset); err != nil {
- return 0, nil, err
- }
- }
-
- if !flagsOut.Write {
- return 0, nil, syserror.EBADF
- }
-
- if flagsOut.Append {
- return 0, nil, syserror.EINVAL
- }
-
- switch fileIn.FileOperations.(type) {
- case *pipe.Reader, *pipe.ReaderWriter:
- // If the pipe in is a Reader or ReaderWriter, we can continue.
- default:
- return 0, nil, syserror.EBADF
- }
- spliced, err := spliceWrite(t, fileIn, fileOut, size, offset, flags)
- if err != nil {
- return 0, nil, err
- }
-
- // Make sure value that offset points to is updated.
- if offOut == 0 {
- fileOut.Seek(t, fs.SeekSet, spliced+int64(offset))
- } else if _, err := t.CopyOut(offOut, spliced+int64(offset)); err != nil {
- return 0, nil, err
- }
- return uintptr(spliced), nil, nil
- }
-
- // Check if the file descriptor that the data will be moved to is a pipe.
- if opipe {
- flagsIn := fileIn.Flags()
- offset := uint64(fileIn.Offset())
-
- // If there is an offset for the file, ensure the file has the Pread flag.
- if offIn != 0 {
- if !flagsIn.Pread {
- return 0, nil, syserror.EINVAL
- }
- if _, err := t.CopyIn(offIn, &offset); err != nil {
- return 0, nil, err
- }
- }
-
- if !flagsIn.Read {
- return 0, nil, syserror.EBADF
- }
-
- switch fileOut.FileOperations.(type) {
- case *pipe.Writer, *pipe.ReaderWriter:
- // If the pipe out is a Writer or ReaderWriter, we can continue.
- default:
- return 0, nil, syserror.EBADF
- }
- spliced, err := spliceRead(t, fileIn, fileOut, size, offset, flags)
- if err != nil {
- return 0, nil, err
- }
-
- // Make sure value that offset points to is updated.
- if offIn == 0 {
- fileOut.Seek(t, fs.SeekSet, spliced+int64(offset))
- } else if _, err := t.CopyOut(offIn, spliced+int64(offset)); err != nil {
- return 0, nil, err
- }
- return uintptr(spliced), nil, nil
- }
-
- // Splice requires one of the file descriptors to be a pipe.
- return 0, nil, syserror.EINVAL
-}
-
-// splicePipeToPipe moves data from one pipe to another pipe.
-// TODO: Implement with zero copy movement/without copying between
-// user and kernel address spaces.
-func splicePipeToPipe(t *kernel.Task, inPipe *fs.File, outPipe *fs.File, size int64, flags uint) (int64, error) {
- w := &fs.FileWriter{t, outPipe}
- if flags == linux.SPLICE_F_NONBLOCK {
- r := &io.LimitedReader{R: &fs.FileReader{t, inPipe}, N: size}
- return io.Copy(w, r)
- }
- var n int64
- for read := int64(0); read < size; {
- var err error
- r := &io.LimitedReader{R: &fs.FileReader{t, inPipe}, N: size}
- n, err = io.Copy(w, r)
- if err != nil && err != syserror.ErrWouldBlock {
- return 0, err
- }
- read += n
- }
- return n, nil
-}
-
-// spliceRead moves data from a file to a pipe.
-// TODO: Implement with zero copy movement/without copying between
-// user and kernel address spaces.
-func spliceRead(t *kernel.Task, inFile *fs.File, outPipe *fs.File, size int64, offset uint64, flags uint) (int64, error) {
- w := &fs.FileWriter{t, outPipe}
- if flags == linux.SPLICE_F_NONBLOCK {
- r := io.NewSectionReader(&fs.FileReader{t, inFile}, int64(offset), size)
- return io.Copy(w, r)
- }
- var n int64
- for read := int64(0); read < size; {
- r := io.NewSectionReader(&fs.FileReader{t, inFile}, int64(offset), size)
- var err error
- n, err = io.Copy(w, r)
- if err != nil && err != syserror.ErrWouldBlock {
- return 0, err
- }
- read += n
- }
- return n, nil
-}
-
-// offsetWriter implements io.Writer on a section of an underlying
-// WriterAt starting from the offset and ending at the limit.
-type offsetWriter struct {
- w io.WriterAt
- off int64
- limit int64
-}
-
-// Write implements io.Writer.Write and writes the content of the offsetWriter
-// starting at the offset and ending at the limit into the given buffer.
-func (o *offsetWriter) Write(p []byte) (n int, err error) {
- if o.off >= o.limit {
- return 0, io.EOF
- }
- if max := o.limit - o.off; int64(len(p)) > max {
- p = p[0:max]
- }
- n, err = o.w.WriteAt(p, o.off)
- o.off += int64(n)
- return n, err
-}
-
-// spliceWrite moves data from a pipe to a file.
-// TODO: Implement with zero copy movement/without copying between
-// user and kernel address spaces.
-func spliceWrite(t *kernel.Task, inPipe *fs.File, outFile *fs.File, size int64, offset uint64, flags uint) (int64, error) {
- w := &offsetWriter{&fs.FileWriter{t, outFile}, int64(offset), int64(offset) + size}
- if flags == linux.SPLICE_F_NONBLOCK {
- r := &io.LimitedReader{R: &fs.FileReader{t, inPipe}, N: size}
- return io.Copy(w, r)
- }
- var n int64
- for read := int64(0); read < size; {
- var err error
- r := &io.LimitedReader{R: &fs.FileReader{t, inPipe}, N: size}
- n, err = io.Copy(w, r)
- if err != nil && err != syserror.ErrWouldBlock {
- return 0, err
- }
- read += n
- }
- return n, nil
-}