summaryrefslogtreecommitdiffhomepage
path: root/pkg/fspath
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/fspath')
-rw-r--r--pkg/fspath/BUILD29
-rw-r--r--pkg/fspath/builder.go104
-rw-r--r--pkg/fspath/builder_test.go58
-rw-r--r--pkg/fspath/builder_unsafe.go27
-rw-r--r--pkg/fspath/fspath.go182
-rw-r--r--pkg/fspath/fspath_test.go143
6 files changed, 0 insertions, 543 deletions
diff --git a/pkg/fspath/BUILD b/pkg/fspath/BUILD
deleted file mode 100644
index 0c5f50397..000000000
--- a/pkg/fspath/BUILD
+++ /dev/null
@@ -1,29 +0,0 @@
-load("//tools/go_stateify:defs.bzl", "go_library")
-load("@io_bazel_rules_go//go:def.bzl", "go_test")
-
-package(
- default_visibility = ["//visibility:public"],
- licenses = ["notice"],
-)
-
-go_library(
- name = "fspath",
- srcs = [
- "builder.go",
- "builder_unsafe.go",
- "fspath.go",
- ],
- importpath = "gvisor.dev/gvisor/pkg/fspath",
- deps = ["//pkg/syserror"],
-)
-
-go_test(
- name = "fspath_test",
- size = "small",
- srcs = [
- "builder_test.go",
- "fspath_test.go",
- ],
- embed = [":fspath"],
- deps = ["//pkg/syserror"],
-)
diff --git a/pkg/fspath/builder.go b/pkg/fspath/builder.go
deleted file mode 100644
index 7ddb36826..000000000
--- a/pkg/fspath/builder.go
+++ /dev/null
@@ -1,104 +0,0 @@
-// 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"
-)
-
-// 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)
-}
diff --git a/pkg/fspath/builder_test.go b/pkg/fspath/builder_test.go
deleted file mode 100644
index 22f890273..000000000
--- a/pkg/fspath/builder_test.go
+++ /dev/null
@@ -1,58 +0,0 @@
-// 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 (
- "testing"
-)
-
-func TestBuilder(t *testing.T) {
- type testCase struct {
- pcs []string // path components in reverse order
- after string
- want string
- }
- tests := []testCase{
- {
- // Empty case.
- },
- {
- pcs: []string{"foo"},
- want: "foo",
- },
- {
- pcs: []string{"foo", "bar", "baz"},
- want: "baz/bar/foo",
- },
- {
- pcs: []string{"foo", "bar"},
- after: " (deleted)",
- want: "bar/foo (deleted)",
- },
- }
-
- for _, test := range tests {
- t.Run(test.want, func(t *testing.T) {
- var b Builder
- for _, pc := range test.pcs {
- b.PrependComponent(pc)
- }
- b.AppendString(test.after)
- if got := b.String(); got != test.want {
- t.Errorf("got %q, wanted %q", got, test.want)
- }
- })
- }
-}
diff --git a/pkg/fspath/builder_unsafe.go b/pkg/fspath/builder_unsafe.go
deleted file mode 100644
index 75606808d..000000000
--- a/pkg/fspath/builder_unsafe.go
+++ /dev/null
@@ -1,27 +0,0 @@
-// 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 (
- "unsafe"
-)
-
-// String returns the accumulated string. No other methods should be called
-// after String.
-func (b *Builder) String() string {
- bs := b.buf[b.start:]
- // Compare strings.Builder.String().
- return *(*string)(unsafe.Pointer(&bs))
-}
diff --git a/pkg/fspath/fspath.go b/pkg/fspath/fspath.go
deleted file mode 100644
index f68752560..000000000
--- a/pkg/fspath/fspath.go
+++ /dev/null
@@ -1,182 +0,0 @@
-// 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 provides efficient tools for working with file paths in
-// Linux-compatible filesystem implementations.
-package fspath
-
-import (
- "strings"
-
- "gvisor.dev/gvisor/pkg/syserror"
-)
-
-const pathSep = '/'
-
-// Parse parses a pathname as described by path_resolution(7).
-func Parse(pathname string) (Path, error) {
- if len(pathname) == 0 {
- // "... POSIX decrees that an empty pathname must not be resolved
- // successfully. Linux returns ENOENT in this case." -
- // path_resolution(7)
- return Path{}, syserror.ENOENT
- }
- // Skip leading path separators.
- i := 0
- for pathname[i] == pathSep {
- i++
- if i == len(pathname) {
- // pathname consists entirely of path separators.
- return Path{
- Absolute: true,
- Dir: true,
- }, nil
- }
- }
- // Skip trailing path separators. This is required by Iterator.Next. This
- // loop is guaranteed to terminate with j >= 0 because otherwise the
- // pathname would consist entirely of path separators, so we would have
- // returned above.
- j := len(pathname) - 1
- for pathname[j] == pathSep {
- j--
- }
- // Find the end of the first path component.
- firstEnd := i + 1
- for firstEnd != len(pathname) && pathname[firstEnd] != pathSep {
- firstEnd++
- }
- return Path{
- Begin: Iterator{
- partialPathname: pathname[i : j+1],
- end: firstEnd - i,
- },
- Absolute: i != 0,
- Dir: j != len(pathname)-1,
- }, nil
-}
-
-// Path contains the information contained in a pathname string.
-//
-// Path is copyable by value.
-type Path struct {
- // Begin is an iterator to the first path component in the relative part of
- // the path.
- //
- // Path doesn't store information about path components after the first
- // since this would require allocation.
- Begin Iterator
-
- // If true, the path is absolute, such that lookup should begin at the
- // filesystem root. If false, the path is relative, such that where lookup
- // begins is unspecified.
- Absolute bool
-
- // If true, the pathname contains trailing path separators, so the last
- // path component must exist and resolve to a directory.
- Dir bool
-}
-
-// String returns a pathname string equivalent to p. Note that the returned
-// string is not necessarily equal to the string p was parsed from; in
-// particular, redundant path separators will not be present.
-func (p Path) String() string {
- var b strings.Builder
- if p.Absolute {
- b.WriteByte(pathSep)
- }
- sep := false
- for pit := p.Begin; pit.Ok(); pit = pit.Next() {
- if sep {
- b.WriteByte(pathSep)
- }
- b.WriteString(pit.String())
- sep = true
- }
- // Don't return "//" for Parse("/").
- if p.Dir && p.Begin.Ok() {
- b.WriteByte(pathSep)
- }
- return b.String()
-}
-
-// An Iterator represents either a path component in a Path or a terminal
-// iterator indicating that the end of the path has been reached.
-//
-// Iterator is immutable and copyable by value. The zero value of Iterator is
-// valid, and represents a terminal iterator.
-type Iterator struct {
- // partialPathname is a substring of the original pathname beginning at the
- // start of the represented path component and ending immediately after the
- // end of the last path component in the pathname. If partialPathname is
- // empty, the PathnameIterator is terminal.
- //
- // See TestParseIteratorPartialPathnames in fspath_test.go for a worked
- // example.
- partialPathname string
-
- // end is the offset into partialPathname of the first byte after the end
- // of the represented path component.
- end int
-}
-
-// Ok returns true if it is not terminal.
-func (it Iterator) Ok() bool {
- return len(it.partialPathname) != 0
-}
-
-// String returns the path component represented by it.
-//
-// Preconditions: it.Ok().
-func (it Iterator) String() string {
- return it.partialPathname[:it.end]
-}
-
-// Next returns an iterator to the path component after it. If it is the last
-// component in the path, Next returns a terminal iterator.
-//
-// Preconditions: it.Ok().
-func (it Iterator) Next() Iterator {
- if it.end == len(it.partialPathname) {
- // End of the path.
- return Iterator{}
- }
- // Skip path separators. Since Parse trims trailing path separators, if we
- // aren't at the end of the path, there is definitely another path
- // component.
- i := it.end + 1
- for {
- if it.partialPathname[i] != pathSep {
- break
- }
- i++
- }
- nextPartialPathname := it.partialPathname[i:]
- // Find the end of this path component.
- nextEnd := 1
- for nextEnd < len(nextPartialPathname) && nextPartialPathname[nextEnd] != pathSep {
- nextEnd++
- }
- return Iterator{
- partialPathname: nextPartialPathname,
- end: nextEnd,
- }
-}
-
-// NextOk is equivalent to it.Next().Ok(), but is faster.
-//
-// Preconditions: it.Ok().
-func (it Iterator) NextOk() bool {
- return it.end != len(it.partialPathname)
-}
diff --git a/pkg/fspath/fspath_test.go b/pkg/fspath/fspath_test.go
deleted file mode 100644
index 215b35622..000000000
--- a/pkg/fspath/fspath_test.go
+++ /dev/null
@@ -1,143 +0,0 @@
-// 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 (
- "reflect"
- "strings"
- "testing"
-
- "gvisor.dev/gvisor/pkg/syserror"
-)
-
-func TestParseIteratorPartialPathnames(t *testing.T) {
- path, err := Parse("/foo//bar///baz////")
- if err != nil {
- t.Fatalf("Parse failed: %v", err)
- }
- // Parse strips leading slashes, and records their presence as
- // Path.Absolute.
- if !path.Absolute {
- t.Errorf("Path.Absolute: got false, wanted true")
- }
- // Parse strips trailing slashes, and records their presence as Path.Dir.
- if !path.Dir {
- t.Errorf("Path.Dir: got false, wanted true")
- }
- // The first Iterator.partialPathname is the input pathname, with leading
- // and trailing slashes stripped.
- it := path.Begin
- if want := "foo//bar///baz"; it.partialPathname != want {
- t.Errorf("first Iterator.partialPathname: got %q, wanted %q", it.partialPathname, want)
- }
- // Successive Iterator.partialPathnames remove the leading path component
- // and following slashes, until we run out of path components and get a
- // terminal Iterator.
- it = it.Next()
- if want := "bar///baz"; it.partialPathname != want {
- t.Errorf("second Iterator.partialPathname: got %q, wanted %q", it.partialPathname, want)
- }
- it = it.Next()
- if want := "baz"; it.partialPathname != want {
- t.Errorf("third Iterator.partialPathname: got %q, wanted %q", it.partialPathname, want)
- }
- it = it.Next()
- if want := ""; it.partialPathname != want {
- t.Errorf("fourth Iterator.partialPathname: got %q, wanted %q", it.partialPathname, want)
- }
- if it.Ok() {
- t.Errorf("fourth Iterator.Ok(): got true, wanted false")
- }
-}
-
-func TestParse(t *testing.T) {
- type testCase struct {
- pathname string
- relpath []string
- abs bool
- dir bool
- }
- tests := []testCase{
- {
- pathname: "/",
- relpath: []string{},
- abs: true,
- dir: true,
- },
- {
- pathname: "//",
- relpath: []string{},
- abs: true,
- dir: true,
- },
- }
- for _, sep := range []string{"/", "//"} {
- for _, abs := range []bool{false, true} {
- for _, dir := range []bool{false, true} {
- for _, pcs := range [][]string{
- // single path component
- {"foo"},
- // multiple path components, including non-UTF-8
- {".", "foo", "..", "\xe6", "bar"},
- } {
- prefix := ""
- if abs {
- prefix = sep
- }
- suffix := ""
- if dir {
- suffix = sep
- }
- tests = append(tests, testCase{
- pathname: prefix + strings.Join(pcs, sep) + suffix,
- relpath: pcs,
- abs: abs,
- dir: dir,
- })
- }
- }
- }
- }
-
- for _, test := range tests {
- t.Run(test.pathname, func(t *testing.T) {
- p, err := Parse(test.pathname)
- if err != nil {
- t.Fatalf("failed to parse pathname %q: %v", test.pathname, err)
- }
- t.Logf("pathname %q => path %q", test.pathname, p)
- if p.Absolute != test.abs {
- t.Errorf("path absoluteness: got %v, wanted %v", p.Absolute, test.abs)
- }
- if p.Dir != test.dir {
- t.Errorf("path must resolve to a directory: got %v, wanted %v", p.Dir, test.dir)
- }
- pcs := []string{}
- for pit := p.Begin; pit.Ok(); pit = pit.Next() {
- pcs = append(pcs, pit.String())
- }
- if !reflect.DeepEqual(pcs, test.relpath) {
- t.Errorf("relative path: got %v, wanted %v", pcs, test.relpath)
- }
- })
- }
-}
-
-func TestParseEmptyPathname(t *testing.T) {
- p, err := Parse("")
- if err != syserror.ENOENT {
- t.Errorf("parsing empty pathname: got (%v, %v), wanted (<unspecified>, ENOENT)", p, err)
- }
-}