Skip to content

Commit fd0edd5

Browse files
committed
helper: chroot dedicated test
1 parent 4826e79 commit fd0edd5

File tree

10 files changed

+606
-175
lines changed

10 files changed

+606
-175
lines changed

fs.go

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -18,23 +18,12 @@ var (
1818
// at the os package from the standard library.
1919
type Filesystem interface {
2020
Basic
21+
TempFile
2122
Dir
2223
Symlink
23-
TempFile
2424
Chroot
2525
}
2626

27-
// Chroot abstract the chroot related operations in a storage-agnostic interface
28-
// as an extension to the Basic interface.
29-
type Chroot interface {
30-
// Chroot returns a new filesystem from the same type where the new root is
31-
// the given path. Files outside of the designated directory tree cannot be
32-
// accessed.
33-
Chroot(path string) (Basic, error)
34-
// Root returns the root path of the filesystem.
35-
Root() string
36-
}
37-
3827
// Basic abstract the basic operations in a storage-agnostic interface as
3928
// an extension to the Basic interface.
4029
type Basic interface {
@@ -72,8 +61,14 @@ type Basic interface {
7261
}
7362

7463
type TempFile interface {
75-
// TempDir returns the default directory to use for temporary files.
76-
//TempDir() string
64+
// TempFile creates a new temporary file in the directory dir with a name
65+
// beginning with prefix, opens the file for reading and writing, and
66+
// returns the resulting *os.File. If dir is the empty string, TempFile
67+
// uses the default directory for temporary files (see os.TempDir).
68+
// Multiple programs calling TempFile simultaneously will not choose the
69+
// same file. The caller can use f.Name() to find the pathname of the file.
70+
// It is the caller's responsibility to remove the file when no longer
71+
// needed.
7772
TempFile(dir, prefix string) (File, error)
7873
}
7974

@@ -129,19 +124,31 @@ type Change interface {
129124
Chtimes(name string, atime time.Time, mtime time.Time) error
130125
}
131126

127+
// Chroot abstract the chroot related operations in a storage-agnostic interface
128+
// as an extension to the Basic interface.
129+
type Chroot interface {
130+
// Chroot returns a new filesystem from the same type where the new root is
131+
// the given path. Files outside of the designated directory tree cannot be
132+
// accessed.
133+
Chroot(path string) (Basic, error)
134+
// Root returns the root path of the filesystem.
135+
Root() string
136+
}
137+
138+
type underlying interface {
139+
Underlying() Basic
140+
}
141+
type removerAll interface {
142+
RemoveAll(string) error
143+
}
144+
132145
// File represent a file, being a subset of the os.File
133146
type File interface {
134147
// Name returns the name of the file as presented to Open.
135148
Name() string
136-
// Stat returns the FileInfo structure describing file. If there is an
137-
// error, it will be of type *PathError.
138-
// Stat() (os.FileInfo, error)
139149
io.Writer
140150
io.Reader
151+
io.ReaderAt
141152
io.Seeker
142153
io.Closer
143154
}
144-
145-
type removerAll interface {
146-
RemoveAll(string) error
147-
}

helper/chroot/chroot.go

Lines changed: 87 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,33 @@
11
package chroot
22

33
import (
4-
"errors"
54
"os"
65
"path/filepath"
76
"strings"
87

98
"gopkg.in/src-d/go-billy.v2"
109
)
1110

12-
// ErrSymlinkNotSupported is returned by Symlink() and Readfile() if the
13-
// underlying filesystem does not support symlinking.
14-
var ErrSymlinkNotSupported = errors.New("symlink not supported")
15-
1611
// ChrootHelper is a helper to implement billy.Chroot.
1712
type ChrootHelper struct {
18-
underlying billy.Filesystem
13+
underlying billy.Basic
1914
base string
15+
16+
tempFileSupport bool
17+
dirSupport bool
18+
symlinkSupport bool
2019
}
2120

2221
// New creates a new filesystem wrapping up the given 'fs'.
2322
// The created filesystem has its base in the given ChrootHelperectory of the
2423
// underlying filesystem.
25-
func New(fs billy.Filesystem, base string) billy.Filesystem {
26-
return &ChrootHelper{fs, base}
24+
func New(fs billy.Basic, base string) billy.Filesystem {
25+
helper := &ChrootHelper{underlying: fs, base: base}
26+
_, helper.tempFileSupport = fs.(billy.TempFile)
27+
_, helper.dirSupport = fs.(billy.Dir)
28+
_, helper.symlinkSupport = fs.(billy.Symlink)
29+
30+
return helper
2731
}
2832

2933
func (fs *ChrootHelper) underlyingPath(filename string) (string, error) {
@@ -83,18 +87,13 @@ func (fs *ChrootHelper) OpenFile(filename string, flag int, mode os.FileMode) (b
8387
return newFile(fs, f, filename), nil
8488
}
8589

86-
func (fs *ChrootHelper) TempFile(dir, prefix string) (billy.File, error) {
87-
fullpath, err := fs.underlyingPath(dir)
88-
if err != nil {
89-
return nil, err
90-
}
91-
92-
f, err := fs.underlying.TempFile(fullpath, prefix)
90+
func (fs *ChrootHelper) Stat(filename string) (os.FileInfo, error) {
91+
fullpath, err := fs.underlyingPath(filename)
9392
if err != nil {
9493
return nil, err
9594
}
9695

97-
return newFile(fs, f, fs.Join(dir, filepath.Base(f.Name()))), nil
96+
return fs.underlying.Stat(fullpath)
9897
}
9998

10099
func (fs *ChrootHelper) Rename(from, to string) error {
@@ -121,52 +120,78 @@ func (fs *ChrootHelper) Remove(path string) error {
121120
return fs.underlying.Remove(fullpath)
122121
}
123122

124-
func (fs *ChrootHelper) MkdirAll(filename string, perm os.FileMode) error {
125-
fullpath, err := fs.underlyingPath(filename)
123+
func (fs *ChrootHelper) Join(elem ...string) string {
124+
return fs.underlying.Join(elem...)
125+
}
126+
127+
func (fs *ChrootHelper) TempFile(dir, prefix string) (billy.File, error) {
128+
if !fs.tempFileSupport {
129+
return nil, billy.ErrNotSupported
130+
}
131+
132+
fullpath, err := fs.underlyingPath(dir)
126133
if err != nil {
127-
return err
134+
return nil, err
128135
}
129136

130-
return fs.underlying.MkdirAll(fullpath, perm)
137+
f, err := fs.underlying.(billy.TempFile).TempFile(fullpath, prefix)
138+
if err != nil {
139+
return nil, err
140+
}
141+
142+
return newFile(fs, f, fs.Join(dir, filepath.Base(f.Name()))), nil
131143
}
132144

133-
func (fs *ChrootHelper) Stat(filename string) (os.FileInfo, error) {
134-
fullpath, err := fs.underlyingPath(filename)
145+
func (fs *ChrootHelper) ReadDir(path string) ([]os.FileInfo, error) {
146+
if !fs.dirSupport {
147+
return nil, billy.ErrNotSupported
148+
}
149+
150+
fullpath, err := fs.underlyingPath(path)
135151
if err != nil {
136152
return nil, err
137153
}
138154

139-
return fs.underlying.Stat(fullpath)
155+
return fs.underlying.(billy.Dir).ReadDir(fullpath)
140156
}
141157

142-
func (fs *ChrootHelper) Lstat(filename string) (os.FileInfo, error) {
158+
func (fs *ChrootHelper) MkdirAll(filename string, perm os.FileMode) error {
159+
if !fs.dirSupport {
160+
return billy.ErrNotSupported
161+
}
162+
143163
fullpath, err := fs.underlyingPath(filename)
144164
if err != nil {
145-
return nil, err
165+
return err
146166
}
147167

148-
return fs.underlying.Lstat(fullpath)
168+
return fs.underlying.(billy.Dir).MkdirAll(fullpath, perm)
149169
}
150170

151-
func (fs *ChrootHelper) ReadDir(path string) ([]os.FileInfo, error) {
152-
fullpath, err := fs.underlyingPath(path)
171+
func (fs *ChrootHelper) Lstat(filename string) (os.FileInfo, error) {
172+
if !fs.symlinkSupport {
173+
return nil, billy.ErrNotSupported
174+
}
175+
176+
fullpath, err := fs.underlyingPath(filename)
153177
if err != nil {
154178
return nil, err
155179
}
156180

157-
return fs.underlying.ReadDir(fullpath)
158-
}
159-
160-
func (fs *ChrootHelper) Join(elem ...string) string {
161-
return fs.underlying.Join(elem...)
181+
return fs.underlying.(billy.Symlink).Lstat(fullpath)
162182
}
163183

164184
func (fs *ChrootHelper) Symlink(target, link string) error {
185+
if !fs.symlinkSupport {
186+
return billy.ErrNotSupported
187+
}
188+
165189
target = filepath.FromSlash(target)
166190

167191
// only rewrite target if it's already absolute
168192
if filepath.IsAbs(target) || strings.HasPrefix(target, string(filepath.Separator)) {
169193
target = fs.Join(fs.Root(), target)
194+
target = filepath.Clean(filepath.FromSlash(target))
170195
}
171196

172197
if fs.isTargetOutBounders(link, target) {
@@ -178,7 +203,7 @@ func (fs *ChrootHelper) Symlink(target, link string) error {
178203
return err
179204
}
180205

181-
return fs.underlying.Symlink(target, link)
206+
return fs.underlying.(billy.Symlink).Symlink(target, link)
182207
}
183208

184209
func (fs *ChrootHelper) isTargetOutBounders(link, target string) bool {
@@ -193,12 +218,16 @@ func (fs *ChrootHelper) isTargetOutBounders(link, target string) bool {
193218
}
194219

195220
func (fs *ChrootHelper) Readlink(link string) (string, error) {
221+
if !fs.symlinkSupport {
222+
return "", billy.ErrNotSupported
223+
}
224+
196225
fullpath, err := fs.underlyingPath(link)
197226
if err != nil {
198227
return "", err
199228
}
200229

201-
target, err := fs.underlying.Readlink(fullpath)
230+
target, err := fs.underlying.(billy.Symlink).Readlink(fullpath)
202231
if err != nil {
203232
return "", err
204233
}
@@ -227,3 +256,26 @@ func (fs *ChrootHelper) Chroot(path string) (billy.Basic, error) {
227256
func (fs *ChrootHelper) Root() string {
228257
return fs.base
229258
}
259+
260+
func (fs *ChrootHelper) Underlying() billy.Basic {
261+
return fs.underlying
262+
}
263+
264+
type file struct {
265+
billy.File
266+
name string
267+
}
268+
269+
func newFile(fs billy.Filesystem, f billy.File, filename string) billy.File {
270+
filename = fs.Join(fs.Root(), filename)
271+
filename, _ = filepath.Rel(fs.Root(), filename)
272+
273+
return &file{
274+
File: f,
275+
name: filename,
276+
}
277+
}
278+
279+
func (f *file) Name() string {
280+
return f.name
281+
}

0 commit comments

Comments
 (0)