1
1
package chroot
2
2
3
3
import (
4
- "errors"
5
4
"os"
6
5
"path/filepath"
7
6
"strings"
8
7
9
8
"gopkg.in/src-d/go-billy.v2"
10
9
)
11
10
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
-
16
11
// ChrootHelper is a helper to implement billy.Chroot.
17
12
type ChrootHelper struct {
18
- underlying billy.Filesystem
13
+ underlying billy.Basic
19
14
base string
15
+
16
+ tempFileSupport bool
17
+ dirSupport bool
18
+ symlinkSupport bool
20
19
}
21
20
22
21
// New creates a new filesystem wrapping up the given 'fs'.
23
22
// The created filesystem has its base in the given ChrootHelperectory of the
24
23
// 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
27
31
}
28
32
29
33
func (fs * ChrootHelper ) underlyingPath (filename string ) (string , error ) {
@@ -83,18 +87,13 @@ func (fs *ChrootHelper) OpenFile(filename string, flag int, mode os.FileMode) (b
83
87
return newFile (fs , f , filename ), nil
84
88
}
85
89
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 )
93
92
if err != nil {
94
93
return nil , err
95
94
}
96
95
97
- return newFile ( fs , f , fs . Join ( dir , filepath . Base ( f . Name ()))), nil
96
+ return fs . underlying . Stat ( fullpath )
98
97
}
99
98
100
99
func (fs * ChrootHelper ) Rename (from , to string ) error {
@@ -121,52 +120,78 @@ func (fs *ChrootHelper) Remove(path string) error {
121
120
return fs .underlying .Remove (fullpath )
122
121
}
123
122
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 )
126
133
if err != nil {
127
- return err
134
+ return nil , err
128
135
}
129
136
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
131
143
}
132
144
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 )
135
151
if err != nil {
136
152
return nil , err
137
153
}
138
154
139
- return fs .underlying .Stat (fullpath )
155
+ return fs .underlying .(billy. Dir ). ReadDir (fullpath )
140
156
}
141
157
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
+
143
163
fullpath , err := fs .underlyingPath (filename )
144
164
if err != nil {
145
- return nil , err
165
+ return err
146
166
}
147
167
148
- return fs .underlying .Lstat ( fullpath )
168
+ return fs .underlying .(billy. Dir ). MkdirAll ( fullpath , perm )
149
169
}
150
170
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 )
153
177
if err != nil {
154
178
return nil , err
155
179
}
156
180
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 )
162
182
}
163
183
164
184
func (fs * ChrootHelper ) Symlink (target , link string ) error {
185
+ if ! fs .symlinkSupport {
186
+ return billy .ErrNotSupported
187
+ }
188
+
165
189
target = filepath .FromSlash (target )
166
190
167
191
// only rewrite target if it's already absolute
168
192
if filepath .IsAbs (target ) || strings .HasPrefix (target , string (filepath .Separator )) {
169
193
target = fs .Join (fs .Root (), target )
194
+ target = filepath .Clean (filepath .FromSlash (target ))
170
195
}
171
196
172
197
if fs .isTargetOutBounders (link , target ) {
@@ -178,7 +203,7 @@ func (fs *ChrootHelper) Symlink(target, link string) error {
178
203
return err
179
204
}
180
205
181
- return fs .underlying .Symlink (target , link )
206
+ return fs .underlying .(billy. Symlink ). Symlink (target , link )
182
207
}
183
208
184
209
func (fs * ChrootHelper ) isTargetOutBounders (link , target string ) bool {
@@ -193,12 +218,16 @@ func (fs *ChrootHelper) isTargetOutBounders(link, target string) bool {
193
218
}
194
219
195
220
func (fs * ChrootHelper ) Readlink (link string ) (string , error ) {
221
+ if ! fs .symlinkSupport {
222
+ return "" , billy .ErrNotSupported
223
+ }
224
+
196
225
fullpath , err := fs .underlyingPath (link )
197
226
if err != nil {
198
227
return "" , err
199
228
}
200
229
201
- target , err := fs .underlying .Readlink (fullpath )
230
+ target , err := fs .underlying .(billy. Symlink ). Readlink (fullpath )
202
231
if err != nil {
203
232
return "" , err
204
233
}
@@ -227,3 +256,26 @@ func (fs *ChrootHelper) Chroot(path string) (billy.Basic, error) {
227
256
func (fs * ChrootHelper ) Root () string {
228
257
return fs .base
229
258
}
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