github.com/nicocha30/gvisor-ligolo@v0.0.0-20230726075806-989fa2c0a413/pkg/sentry/hostfd/hostfd.go (about) 1 // Copyright 2020 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Package hostfd provides efficient I/O with host file descriptors. 16 package hostfd 17 18 import ( 19 "github.com/nicocha30/gvisor-ligolo/pkg/safemem" 20 "github.com/nicocha30/gvisor-ligolo/pkg/sync" 21 ) 22 23 // ReadWriterAt implements safemem.Reader and safemem.Writer by reading from 24 // and writing to a host file descriptor respectively. ReadWriterAts should be 25 // obtained by calling GetReadWriterAt. 26 // 27 // Clients should usually prefer to use Preadv2 and Pwritev2 directly. 28 type ReadWriterAt struct { 29 fd int32 30 offset int64 31 flags uint32 32 } 33 34 var rwpool = sync.Pool{ 35 New: func() any { 36 return &ReadWriterAt{} 37 }, 38 } 39 40 // GetReadWriterAt returns a ReadWriterAt that reads from / writes to the given 41 // host file descriptor, starting at the given offset and using the given 42 // preadv2(2)/pwritev2(2) flags. If offset is -1, the host file descriptor's 43 // offset is used instead. Users are responsible for ensuring that fd remains 44 // valid for the lifetime of the returned ReadWriterAt, and must call 45 // PutReadWriterAt when it is no longer needed. 46 func GetReadWriterAt(fd int32, offset int64, flags uint32) *ReadWriterAt { 47 rw := rwpool.Get().(*ReadWriterAt) 48 *rw = ReadWriterAt{ 49 fd: fd, 50 offset: offset, 51 flags: flags, 52 } 53 return rw 54 } 55 56 // PutReadWriterAt releases a ReadWriterAt returned by a previous call to 57 // GetReadWriterAt that is no longer in use. 58 func PutReadWriterAt(rw *ReadWriterAt) { 59 rwpool.Put(rw) 60 } 61 62 // ReadToBlocks implements safemem.Reader.ReadToBlocks. 63 func (rw *ReadWriterAt) ReadToBlocks(dsts safemem.BlockSeq) (uint64, error) { 64 if dsts.IsEmpty() { 65 return 0, nil 66 } 67 n, err := Preadv2(rw.fd, dsts, rw.offset, rw.flags) 68 if rw.offset >= 0 { 69 rw.offset += int64(n) 70 } 71 return n, err 72 } 73 74 // WriteFromBlocks implements safemem.Writer.WriteFromBlocks. 75 func (rw *ReadWriterAt) WriteFromBlocks(srcs safemem.BlockSeq) (uint64, error) { 76 if srcs.IsEmpty() { 77 return 0, nil 78 } 79 n, err := Pwritev2(rw.fd, srcs, rw.offset, rw.flags) 80 if rw.offset >= 0 { 81 rw.offset += int64(n) 82 } 83 return n, err 84 }