Files
Jamie Liu 471b15b212 Port most syscalls to VFS2.
pipe and pipe2 aren't ported, pending a slight rework of pipe FDs for VFS2.
mount and umount2 aren't ported out of temporary laziness. access and faccessat
need additional FSImpl methods to implement properly, but are stubbed to
prevent googletest from CHECK-failing. Other syscalls require additional
plumbing.

Updates #1623

PiperOrigin-RevId: 297188448
2020-02-25 13:37:34 -08:00

113 lines
2.8 KiB
Go

// Copyright 2019 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 fspath
import (
"fmt"
"gvisor.dev/gvisor/pkg/gohacks"
)
// Builder is similar to strings.Builder, but is used to produce pathnames
// given path components in reverse order (from leaf to root). This is useful
// in the common case where a filesystem is represented by a tree of named
// nodes, and the path to a given node must be produced by walking upward from
// that node to a given root.
type Builder struct {
buf []byte
start int
needSep bool
}
// Reset resets the Builder to be empty.
func (b *Builder) Reset() {
b.start = len(b.buf)
b.needSep = false
}
// Len returns the number of accumulated bytes.
func (b *Builder) Len() int {
return len(b.buf) - b.start
}
func (b *Builder) needToGrow(n int) bool {
return b.start < n
}
func (b *Builder) grow(n int) {
newLen := b.Len() + n
var newCap int
if len(b.buf) == 0 {
newCap = 64 // arbitrary
} else {
newCap = 2 * len(b.buf)
}
for newCap < newLen {
newCap *= 2
if newCap == 0 {
panic(fmt.Sprintf("required length (%d) causes buffer size to overflow", newLen))
}
}
newBuf := make([]byte, newCap)
copy(newBuf[newCap-b.Len():], b.buf[b.start:])
b.start += newCap - len(b.buf)
b.buf = newBuf
}
// PrependComponent prepends the given path component to b's buffer. A path
// separator is automatically inserted if appropriate.
func (b *Builder) PrependComponent(pc string) {
if b.needSep {
b.PrependByte('/')
}
b.PrependString(pc)
b.needSep = true
}
// PrependString prepends the given string to b's buffer.
func (b *Builder) PrependString(str string) {
if b.needToGrow(len(str)) {
b.grow(len(str))
}
b.start -= len(str)
copy(b.buf[b.start:], str)
}
// PrependByte prepends the given byte to b's buffer.
func (b *Builder) PrependByte(c byte) {
if b.needToGrow(1) {
b.grow(1)
}
b.start--
b.buf[b.start] = c
}
// AppendString appends the given string to b's buffer.
func (b *Builder) AppendString(str string) {
if b.needToGrow(len(str)) {
b.grow(len(str))
}
oldStart := b.start
b.start -= len(str)
copy(b.buf[b.start:], b.buf[oldStart:])
copy(b.buf[len(b.buf)-len(str):], str)
}
// String returns the accumulated string. No other methods should be called
// after String.
func (b *Builder) String() string {
return gohacks.StringFromImmutableBytes(b.buf[b.start:])
}