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  }