Skip to content

Commit d48e2a7

Browse files
authored
Merge pull request #35 from mcuadros/polyfill
helper: new polyfill helper, and mount and chroot simplification
2 parents bfa45f0 + 672c9bf commit d48e2a7

File tree

6 files changed

+182
-70
lines changed

6 files changed

+182
-70
lines changed

fs.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ type Chroot interface {
121121
// Chroot returns a new filesystem from the same type where the new root is
122122
// the given path. Files outside of the designated directory tree cannot be
123123
// accessed.
124-
Chroot(path string) (Basic, error)
124+
Chroot(path string) (Filesystem, error)
125125
// Root returns the root path of the filesystem.
126126
Root() string
127127
}

helper/chroot/chroot.go

Lines changed: 7 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -6,28 +6,23 @@ import (
66
"strings"
77

88
"gopkg.in/src-d/go-billy.v3"
9+
"gopkg.in/src-d/go-billy.v3/helper/polyfill"
910
)
1011

1112
// ChrootHelper is a helper to implement billy.Chroot.
1213
type ChrootHelper struct {
13-
underlying billy.Basic
14+
underlying billy.Filesystem
1415
base string
15-
16-
dirSupport bool
17-
symlinkSupport bool
18-
tempFileSupport bool
1916
}
2017

2118
// New creates a new filesystem wrapping up the given 'fs'.
2219
// The created filesystem has its base in the given ChrootHelperectory of the
2320
// underlying filesystem.
2421
func New(fs billy.Basic, base string) billy.Filesystem {
25-
helper := &ChrootHelper{underlying: fs, base: base}
26-
_, helper.dirSupport = fs.(billy.Dir)
27-
_, helper.symlinkSupport = fs.(billy.Symlink)
28-
_, helper.tempFileSupport = fs.(billy.TempFile)
29-
30-
return helper
22+
return &ChrootHelper{
23+
underlying: polyfill.New(fs),
24+
base: base,
25+
}
3126
}
3227

3328
func (fs *ChrootHelper) underlyingPath(filename string) (string, error) {
@@ -125,10 +120,6 @@ func (fs *ChrootHelper) Join(elem ...string) string {
125120
}
126121

127122
func (fs *ChrootHelper) TempFile(dir, prefix string) (billy.File, error) {
128-
if !fs.tempFileSupport {
129-
return nil, billy.ErrNotSupported
130-
}
131-
132123
fullpath, err := fs.underlyingPath(dir)
133124
if err != nil {
134125
return nil, err
@@ -143,10 +134,6 @@ func (fs *ChrootHelper) TempFile(dir, prefix string) (billy.File, error) {
143134
}
144135

145136
func (fs *ChrootHelper) ReadDir(path string) ([]os.FileInfo, error) {
146-
if !fs.dirSupport {
147-
return nil, billy.ErrNotSupported
148-
}
149-
150137
fullpath, err := fs.underlyingPath(path)
151138
if err != nil {
152139
return nil, err
@@ -156,10 +143,6 @@ func (fs *ChrootHelper) ReadDir(path string) ([]os.FileInfo, error) {
156143
}
157144

158145
func (fs *ChrootHelper) MkdirAll(filename string, perm os.FileMode) error {
159-
if !fs.dirSupport {
160-
return billy.ErrNotSupported
161-
}
162-
163146
fullpath, err := fs.underlyingPath(filename)
164147
if err != nil {
165148
return err
@@ -169,10 +152,6 @@ func (fs *ChrootHelper) MkdirAll(filename string, perm os.FileMode) error {
169152
}
170153

171154
func (fs *ChrootHelper) Lstat(filename string) (os.FileInfo, error) {
172-
if !fs.symlinkSupport {
173-
return nil, billy.ErrNotSupported
174-
}
175-
176155
fullpath, err := fs.underlyingPath(filename)
177156
if err != nil {
178157
return nil, err
@@ -182,10 +161,6 @@ func (fs *ChrootHelper) Lstat(filename string) (os.FileInfo, error) {
182161
}
183162

184163
func (fs *ChrootHelper) Symlink(target, link string) error {
185-
if !fs.symlinkSupport {
186-
return billy.ErrNotSupported
187-
}
188-
189164
target = filepath.FromSlash(target)
190165

191166
// only rewrite target if it's already absolute
@@ -218,10 +193,6 @@ func (fs *ChrootHelper) isTargetOutBounders(link, target string) bool {
218193
}
219194

220195
func (fs *ChrootHelper) Readlink(link string) (string, error) {
221-
if !fs.symlinkSupport {
222-
return "", billy.ErrNotSupported
223-
}
224-
225196
fullpath, err := fs.underlyingPath(link)
226197
if err != nil {
227198
return "", err
@@ -244,7 +215,7 @@ func (fs *ChrootHelper) Readlink(link string) (string, error) {
244215
return string(os.PathSeparator) + target, nil
245216
}
246217

247-
func (fs *ChrootHelper) Chroot(path string) (billy.Basic, error) {
218+
func (fs *ChrootHelper) Chroot(path string) (billy.Filesystem, error) {
248219
fullpath, err := fs.underlyingPath(path)
249220
if err != nil {
250221
return nil, err

helper/chroot/chroot_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ func (s *ChrootSuite) TestSymlinkWithBasic(c *C) {
299299
m := &test.BasicMock{}
300300

301301
fs := New(m, "/foo")
302-
err := fs.Symlink("", "")
302+
err := fs.Symlink("qux", "bar")
303303
c.Assert(err, Equals, billy.ErrNotSupported)
304304
}
305305

helper/mount/mount.go

Lines changed: 10 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"fmt"
1010

1111
"gopkg.in/src-d/go-billy.v3"
12+
"gopkg.in/src-d/go-billy.v3/helper/polyfill"
1213
)
1314

1415
var separator = string(filepath.Separator)
@@ -17,30 +18,19 @@ var separator = string(filepath.Separator)
1718
// Very usufull to create a temporal dir, on filesystem where is a performance
1819
// penalty in doing so.
1920
type Mount struct {
20-
underlying billy.Basic
21-
source billy.Basic
21+
underlying billy.Filesystem
22+
source billy.Filesystem
2223
mountpoint string
23-
24-
uc capabilities // underlying
25-
sc capabilities // source
2624
}
2725

28-
type capabilities struct{ dir, symlink bool }
29-
3026
// New creates a new filesystem wrapping up 'fs' the intercepts all the calls
3127
// made to `mountpoint` path and redirecting it to `source` filesystem.
3228
func New(fs billy.Basic, mountpoint string, source billy.Basic) *Mount {
33-
h := &Mount{
34-
underlying: fs,
35-
source: source,
29+
return &Mount{
30+
underlying: polyfill.New(fs),
31+
source: polyfill.New(source),
3632
mountpoint: cleanPath(mountpoint),
3733
}
38-
39-
_, h.sc.dir = h.source.(billy.Dir)
40-
_, h.sc.symlink = h.source.(billy.Symlink)
41-
_, h.uc.dir = h.underlying.(billy.Dir)
42-
_, h.uc.symlink = h.underlying.(billy.Symlink)
43-
return h
4434
}
4535

4636
func (h *Mount) Create(path string) (billy.File, error) {
@@ -169,6 +159,10 @@ func (h *Mount) Lstat(path string) (os.FileInfo, error) {
169159
return fs.Lstat(fullpath)
170160
}
171161

162+
func (h *Mount) Underlying() billy.Basic {
163+
return h.underlying
164+
}
165+
172166
func (fs *Mount) getBasicAndPath(path string) (billy.Basic, string) {
173167
path = cleanPath(path)
174168
if !fs.isMountpoint(path) {
@@ -181,34 +175,18 @@ func (fs *Mount) getBasicAndPath(path string) (billy.Basic, string) {
181175
func (fs *Mount) getDirAndPath(path string) (billy.Dir, string, error) {
182176
path = cleanPath(path)
183177
if !fs.isMountpoint(path) {
184-
if !fs.uc.dir {
185-
return nil, "", billy.ErrNotSupported
186-
}
187-
188178
return fs.underlying.(billy.Dir), path, nil
189179
}
190180

191-
if !fs.sc.dir {
192-
return nil, "", billy.ErrNotSupported
193-
}
194-
195181
return fs.source.(billy.Dir), fs.mustRelToMountpoint(path), nil
196182
}
197183

198184
func (fs *Mount) getSymlinkAndPath(path string) (billy.Symlink, string, error) {
199185
path = cleanPath(path)
200186
if !fs.isMountpoint(path) {
201-
if !fs.uc.symlink {
202-
return nil, "", billy.ErrNotSupported
203-
}
204-
205187
return fs.underlying.(billy.Symlink), path, nil
206188
}
207189

208-
if !fs.sc.symlink {
209-
return nil, "", billy.ErrNotSupported
210-
}
211-
212190
return fs.source.(billy.Symlink), fs.mustRelToMountpoint(path), nil
213191
}
214192

helper/polyfill/polyfill.go

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
package polyfill
2+
3+
import (
4+
"os"
5+
"path/filepath"
6+
7+
"gopkg.in/src-d/go-billy.v3"
8+
)
9+
10+
// Polyfill is a helper that implements all missing method from billy.Filesystem.
11+
type Polyfill struct {
12+
billy.Basic
13+
c capabilities
14+
}
15+
16+
type capabilities struct{ tempfile, dir, symlink, chroot bool }
17+
18+
// New creates a new filesystem wrapping up 'fs' the intercepts all the calls
19+
// made and errors if fs doesn't implement any of the billy interfaces.
20+
func New(fs billy.Basic) billy.Filesystem {
21+
if original, ok := fs.(billy.Filesystem); ok {
22+
return original
23+
}
24+
25+
h := &Polyfill{Basic: fs}
26+
27+
_, h.c.tempfile = h.Basic.(billy.TempFile)
28+
_, h.c.dir = h.Basic.(billy.Dir)
29+
_, h.c.symlink = h.Basic.(billy.Symlink)
30+
_, h.c.chroot = h.Basic.(billy.Chroot)
31+
return h
32+
}
33+
34+
func (h *Polyfill) TempFile(dir, prefix string) (billy.File, error) {
35+
if !h.c.tempfile {
36+
return nil, billy.ErrNotSupported
37+
}
38+
39+
return h.Basic.(billy.TempFile).TempFile(dir, prefix)
40+
}
41+
42+
func (h *Polyfill) ReadDir(path string) ([]os.FileInfo, error) {
43+
if !h.c.dir {
44+
return nil, billy.ErrNotSupported
45+
}
46+
47+
return h.Basic.(billy.Dir).ReadDir(path)
48+
}
49+
50+
func (h *Polyfill) MkdirAll(filename string, perm os.FileMode) error {
51+
if !h.c.dir {
52+
return billy.ErrNotSupported
53+
}
54+
55+
return h.Basic.(billy.Dir).MkdirAll(filename, perm)
56+
}
57+
58+
func (h *Polyfill) Symlink(target, link string) error {
59+
if !h.c.symlink {
60+
return billy.ErrNotSupported
61+
}
62+
63+
return h.Basic.(billy.Symlink).Symlink(target, link)
64+
}
65+
66+
func (h *Polyfill) Readlink(link string) (string, error) {
67+
if !h.c.symlink {
68+
return "", billy.ErrNotSupported
69+
}
70+
71+
return h.Basic.(billy.Symlink).Readlink(link)
72+
}
73+
74+
func (h *Polyfill) Lstat(path string) (os.FileInfo, error) {
75+
if !h.c.symlink {
76+
return nil, billy.ErrNotSupported
77+
}
78+
79+
return h.Basic.(billy.Symlink).Lstat(path)
80+
}
81+
82+
func (h *Polyfill) Chroot(path string) (billy.Filesystem, error) {
83+
if !h.c.chroot {
84+
return nil, billy.ErrNotSupported
85+
}
86+
87+
return h.Basic.(billy.Chroot).Chroot(path)
88+
}
89+
90+
func (h *Polyfill) Root() string {
91+
if !h.c.chroot {
92+
return string(filepath.Separator)
93+
}
94+
95+
return h.Basic.(billy.Chroot).Root()
96+
}
97+
98+
func (h *Polyfill) Underlying() billy.Basic {
99+
return h.Basic
100+
}

helper/polyfill/polyfill_test.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package polyfill
2+
3+
import (
4+
"path/filepath"
5+
"testing"
6+
7+
"gopkg.in/src-d/go-billy.v3"
8+
"gopkg.in/src-d/go-billy.v3/test"
9+
10+
. "gopkg.in/check.v1"
11+
)
12+
13+
func Test(t *testing.T) { TestingT(t) }
14+
15+
var _ = Suite(&PolyfillSuite{})
16+
17+
type PolyfillSuite struct {
18+
Helper billy.Filesystem
19+
Underlying billy.Filesystem
20+
}
21+
22+
func (s *PolyfillSuite) SetUpTest(c *C) {
23+
s.Helper = New(&test.BasicMock{})
24+
}
25+
26+
func (s *PolyfillSuite) TestTempFile(c *C) {
27+
_, err := s.Helper.TempFile("", "")
28+
c.Assert(err, Equals, billy.ErrNotSupported)
29+
}
30+
31+
func (s *PolyfillSuite) TestReadDir(c *C) {
32+
_, err := s.Helper.ReadDir("")
33+
c.Assert(err, Equals, billy.ErrNotSupported)
34+
}
35+
36+
func (s *PolyfillSuite) TestMkdirAll(c *C) {
37+
err := s.Helper.MkdirAll("", 0)
38+
c.Assert(err, Equals, billy.ErrNotSupported)
39+
}
40+
41+
func (s *PolyfillSuite) TestSymlink(c *C) {
42+
err := s.Helper.Symlink("", "")
43+
c.Assert(err, Equals, billy.ErrNotSupported)
44+
}
45+
46+
func (s *PolyfillSuite) TestReadlink(c *C) {
47+
_, err := s.Helper.Readlink("")
48+
c.Assert(err, Equals, billy.ErrNotSupported)
49+
}
50+
51+
func (s *PolyfillSuite) TestLstat(c *C) {
52+
_, err := s.Helper.Lstat("")
53+
c.Assert(err, Equals, billy.ErrNotSupported)
54+
}
55+
56+
func (s *PolyfillSuite) TestChroot(c *C) {
57+
_, err := s.Helper.Chroot("")
58+
c.Assert(err, Equals, billy.ErrNotSupported)
59+
}
60+
61+
func (s *PolyfillSuite) TestRoot(c *C) {
62+
c.Assert(s.Helper.Root(), Equals, string(filepath.Separator))
63+
}

0 commit comments

Comments
 (0)