| // Copyright 2018 The gVisor Authors. |
| // |
| // 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 usermem |
| |
| import ( |
| "gvisor.dev/gvisor/pkg/context" |
| "gvisor.dev/gvisor/pkg/safemem" |
| "gvisor.dev/gvisor/pkg/syserror" |
| ) |
| |
| const maxInt = int(^uint(0) >> 1) |
| |
| // BytesIO implements IO using a byte slice. Addresses are interpreted as |
| // offsets into the slice. Reads and writes beyond the end of the slice return |
| // EFAULT. |
| type BytesIO struct { |
| Bytes []byte |
| } |
| |
| // CopyOut implements IO.CopyOut. |
| func (b *BytesIO) CopyOut(ctx context.Context, addr Addr, src []byte, opts IOOpts) (int, error) { |
| rngN, rngErr := b.rangeCheck(addr, len(src)) |
| if rngN == 0 { |
| return 0, rngErr |
| } |
| return copy(b.Bytes[int(addr):], src[:rngN]), rngErr |
| } |
| |
| // CopyIn implements IO.CopyIn. |
| func (b *BytesIO) CopyIn(ctx context.Context, addr Addr, dst []byte, opts IOOpts) (int, error) { |
| rngN, rngErr := b.rangeCheck(addr, len(dst)) |
| if rngN == 0 { |
| return 0, rngErr |
| } |
| return copy(dst[:rngN], b.Bytes[int(addr):]), rngErr |
| } |
| |
| // ZeroOut implements IO.ZeroOut. |
| func (b *BytesIO) ZeroOut(ctx context.Context, addr Addr, toZero int64, opts IOOpts) (int64, error) { |
| if toZero > int64(maxInt) { |
| return 0, syserror.EINVAL |
| } |
| rngN, rngErr := b.rangeCheck(addr, int(toZero)) |
| if rngN == 0 { |
| return 0, rngErr |
| } |
| zeroSlice := b.Bytes[int(addr) : int(addr)+rngN] |
| for i := range zeroSlice { |
| zeroSlice[i] = 0 |
| } |
| return int64(rngN), rngErr |
| } |
| |
| // CopyOutFrom implements IO.CopyOutFrom. |
| func (b *BytesIO) CopyOutFrom(ctx context.Context, ars AddrRangeSeq, src safemem.Reader, opts IOOpts) (int64, error) { |
| dsts, rngErr := b.blocksFromAddrRanges(ars) |
| n, err := src.ReadToBlocks(dsts) |
| if err != nil { |
| return int64(n), err |
| } |
| return int64(n), rngErr |
| } |
| |
| // CopyInTo implements IO.CopyInTo. |
| func (b *BytesIO) CopyInTo(ctx context.Context, ars AddrRangeSeq, dst safemem.Writer, opts IOOpts) (int64, error) { |
| srcs, rngErr := b.blocksFromAddrRanges(ars) |
| n, err := dst.WriteFromBlocks(srcs) |
| if err != nil { |
| return int64(n), err |
| } |
| return int64(n), rngErr |
| } |
| |
| func (b *BytesIO) rangeCheck(addr Addr, length int) (int, error) { |
| if length == 0 { |
| return 0, nil |
| } |
| if length < 0 { |
| return 0, syserror.EINVAL |
| } |
| max := Addr(len(b.Bytes)) |
| if addr >= max { |
| return 0, syserror.EFAULT |
| } |
| end, ok := addr.AddLength(uint64(length)) |
| if !ok || end > max { |
| return int(max - addr), syserror.EFAULT |
| } |
| return length, nil |
| } |
| |
| func (b *BytesIO) blocksFromAddrRanges(ars AddrRangeSeq) (safemem.BlockSeq, error) { |
| switch ars.NumRanges() { |
| case 0: |
| return safemem.BlockSeq{}, nil |
| case 1: |
| block, err := b.blockFromAddrRange(ars.Head()) |
| return safemem.BlockSeqOf(block), err |
| default: |
| blocks := make([]safemem.Block, 0, ars.NumRanges()) |
| for !ars.IsEmpty() { |
| block, err := b.blockFromAddrRange(ars.Head()) |
| if block.Len() != 0 { |
| blocks = append(blocks, block) |
| } |
| if err != nil { |
| return safemem.BlockSeqFromSlice(blocks), err |
| } |
| ars = ars.Tail() |
| } |
| return safemem.BlockSeqFromSlice(blocks), nil |
| } |
| } |
| |
| func (b *BytesIO) blockFromAddrRange(ar AddrRange) (safemem.Block, error) { |
| n, err := b.rangeCheck(ar.Start, int(ar.Length())) |
| if n == 0 { |
| return safemem.Block{}, err |
| } |
| return safemem.BlockFromSafeSlice(b.Bytes[int(ar.Start) : int(ar.Start)+n]), err |
| } |
| |
| // BytesIOSequence returns an IOSequence representing the given byte slice. |
| func BytesIOSequence(buf []byte) IOSequence { |
| return IOSequence{ |
| IO: &BytesIO{buf}, |
| Addrs: AddrRangeSeqOf(AddrRange{0, Addr(len(buf))}), |
| } |
| } |