1package test
2
3import (
4	"os"
5
6	. "gopkg.in/check.v1"
7	. "github.com/go-git/go-billy/v5"
8	"github.com/go-git/go-billy/v5/util"
9)
10
11// ChrootSuite is a convenient test suite to validate any implementation of
12// billy.Chroot
13type ChrootSuite struct {
14	FS interface {
15		Basic
16		Chroot
17	}
18}
19
20func (s *ChrootSuite) TestCreateWithChroot(c *C) {
21	fs, _ := s.FS.Chroot("foo")
22	f, err := fs.Create("bar")
23	c.Assert(err, IsNil)
24	c.Assert(f.Close(), IsNil)
25	c.Assert(f.Name(), Equals, "bar")
26
27	f, err = s.FS.Open("foo/bar")
28	c.Assert(err, IsNil)
29	c.Assert(f.Name(), Equals, s.FS.Join("foo", "bar"))
30	c.Assert(f.Close(), IsNil)
31}
32
33func (s *ChrootSuite) TestOpenWithChroot(c *C) {
34	fs, _ := s.FS.Chroot("foo")
35	f, err := fs.Create("bar")
36	c.Assert(err, IsNil)
37	c.Assert(f.Close(), IsNil)
38	c.Assert(f.Name(), Equals, "bar")
39
40	f, err = fs.Open("bar")
41	c.Assert(err, IsNil)
42	c.Assert(f.Name(), Equals, "bar")
43	c.Assert(f.Close(), IsNil)
44}
45
46func (s *ChrootSuite) TestOpenOutOffBoundary(c *C) {
47	err := util.WriteFile(s.FS, "bar", nil, 0644)
48	c.Assert(err, IsNil)
49
50	fs, _ := s.FS.Chroot("foo")
51	f, err := fs.Open("../bar")
52	c.Assert(err, Equals, ErrCrossedBoundary)
53	c.Assert(f, IsNil)
54}
55
56func (s *ChrootSuite) TestStatOutOffBoundary(c *C) {
57	err := util.WriteFile(s.FS, "bar", nil, 0644)
58	c.Assert(err, IsNil)
59
60	fs, _ := s.FS.Chroot("foo")
61	f, err := fs.Stat("../bar")
62	c.Assert(err, Equals, ErrCrossedBoundary)
63	c.Assert(f, IsNil)
64}
65
66func (s *ChrootSuite) TestStatWithChroot(c *C) {
67	files := []string{"foo", "bar", "qux/baz", "qux/qux"}
68	for _, name := range files {
69		err := util.WriteFile(s.FS, name, nil, 0644)
70		c.Assert(err, IsNil)
71	}
72
73	// Some implementations detect directories based on a prefix
74	// for all files; it's easy to miss path separator handling there.
75	fi, err := s.FS.Stat("qu")
76	c.Assert(os.IsNotExist(err), Equals, true, Commentf("error: %s", err))
77	c.Assert(fi, IsNil)
78
79	fi, err = s.FS.Stat("qux")
80	c.Assert(err, IsNil)
81	c.Assert(fi.Name(), Equals, "qux")
82	c.Assert(fi.IsDir(), Equals, true)
83
84	qux, _ := s.FS.Chroot("qux")
85
86	fi, err = qux.Stat("baz")
87	c.Assert(err, IsNil)
88	c.Assert(fi.Name(), Equals, "baz")
89	c.Assert(fi.IsDir(), Equals, false)
90
91	fi, err = qux.Stat("/baz")
92	c.Assert(err, IsNil)
93	c.Assert(fi.Name(), Equals, "baz")
94	c.Assert(fi.IsDir(), Equals, false)
95}
96
97func (s *ChrootSuite) TestRenameOutOffBoundary(c *C) {
98	err := util.WriteFile(s.FS, "foo/foo", nil, 0644)
99	c.Assert(err, IsNil)
100
101	err = util.WriteFile(s.FS, "bar", nil, 0644)
102	c.Assert(err, IsNil)
103
104	fs, _ := s.FS.Chroot("foo")
105	err = fs.Rename("../bar", "foo")
106	c.Assert(err, Equals, ErrCrossedBoundary)
107
108	err = fs.Rename("foo", "../bar")
109	c.Assert(err, Equals, ErrCrossedBoundary)
110}
111
112func (s *ChrootSuite) TestRemoveOutOffBoundary(c *C) {
113	err := util.WriteFile(s.FS, "bar", nil, 0644)
114	c.Assert(err, IsNil)
115
116	fs, _ := s.FS.Chroot("foo")
117	err = fs.Remove("../bar")
118	c.Assert(err, Equals, ErrCrossedBoundary)
119}
120
121func (s *FilesystemSuite) TestRoot(c *C) {
122	c.Assert(s.FS.Root(), Not(Equals), "")
123}
124