20
20
package osfs
21
21
22
22
import (
23
+ "errors"
23
24
"fmt"
24
25
"os"
25
26
"path/filepath"
@@ -29,6 +30,11 @@ import (
29
30
"github.com/go-git/go-billy/v5"
30
31
)
31
32
33
+ var (
34
+ ErrBaseDirCannotBeRemoved = errors .New ("base dir cannot be removed" )
35
+ ErrBaseDirCannotBeRenamed = errors .New ("base dir cannot be renamed" )
36
+ )
37
+
32
38
// BoundOS is a fs implementation based on the OS filesystem which is bound to
33
39
// a base dir.
34
40
// Prefer this fs implementation over ChrootOS.
@@ -54,6 +60,7 @@ func (fs *BoundOS) Create(filename string) (billy.File, error) {
54
60
}
55
61
56
62
func (fs * BoundOS ) OpenFile (filename string , flag int , perm os.FileMode ) (billy.File , error ) {
63
+ filename = fs .expandDot (filename )
57
64
fn , err := fs .abs (filename )
58
65
if err != nil {
59
66
return nil , err
@@ -62,6 +69,7 @@ func (fs *BoundOS) OpenFile(filename string, flag int, perm os.FileMode) (billy.
62
69
}
63
70
64
71
func (fs * BoundOS ) ReadDir (path string ) ([]os.FileInfo , error ) {
72
+ path = fs .expandDot (path )
65
73
dir , err := fs .abs (path )
66
74
if err != nil {
67
75
return nil , err
@@ -71,6 +79,12 @@ func (fs *BoundOS) ReadDir(path string) ([]os.FileInfo, error) {
71
79
}
72
80
73
81
func (fs * BoundOS ) Rename (from , to string ) error {
82
+ if from == "." || from == fs .baseDir {
83
+ return ErrBaseDirCannotBeRenamed
84
+ }
85
+
86
+ from = fs .expandDot (from )
87
+ to = fs .expandDot (to )
74
88
f , err := fs .abs (from )
75
89
if err != nil {
76
90
return err
@@ -89,6 +103,7 @@ func (fs *BoundOS) Rename(from, to string) error {
89
103
}
90
104
91
105
func (fs * BoundOS ) MkdirAll (path string , perm os.FileMode ) error {
106
+ path = fs .expandDot (path )
92
107
dir , err := fs .abs (path )
93
108
if err != nil {
94
109
return err
@@ -97,10 +112,12 @@ func (fs *BoundOS) MkdirAll(path string, perm os.FileMode) error {
97
112
}
98
113
99
114
func (fs * BoundOS ) Open (filename string ) (billy.File , error ) {
115
+ filename = fs .expandDot (filename )
100
116
return fs .OpenFile (filename , os .O_RDONLY , 0 )
101
117
}
102
118
103
119
func (fs * BoundOS ) Stat (filename string ) (os.FileInfo , error ) {
120
+ filename = fs .expandDot (filename )
104
121
filename , err := fs .abs (filename )
105
122
if err != nil {
106
123
return nil , err
@@ -109,6 +126,10 @@ func (fs *BoundOS) Stat(filename string) (os.FileInfo, error) {
109
126
}
110
127
111
128
func (fs * BoundOS ) Remove (filename string ) error {
129
+ if filename == "." || filename == fs .baseDir {
130
+ return ErrBaseDirCannotBeRemoved
131
+ }
132
+
112
133
fn , err := fs .abs (filename )
113
134
if err != nil {
114
135
return err
@@ -136,6 +157,11 @@ func (fs *BoundOS) Join(elem ...string) string {
136
157
}
137
158
138
159
func (fs * BoundOS ) RemoveAll (path string ) error {
160
+ if path == "." || path == fs .baseDir {
161
+ return ErrBaseDirCannotBeRemoved
162
+ }
163
+
164
+ path = fs .expandDot (path )
139
165
dir , err := fs .abs (path )
140
166
if err != nil {
141
167
return err
@@ -144,6 +170,7 @@ func (fs *BoundOS) RemoveAll(path string) error {
144
170
}
145
171
146
172
func (fs * BoundOS ) Symlink (target , link string ) error {
173
+ link = fs .expandDot (link )
147
174
ln , err := fs .abs (link )
148
175
if err != nil {
149
176
return err
@@ -155,7 +182,20 @@ func (fs *BoundOS) Symlink(target, link string) error {
155
182
return os .Symlink (target , ln )
156
183
}
157
184
185
+ func (fs * BoundOS ) expandDot (p string ) string {
186
+ if p == "." {
187
+ return fs .baseDir
188
+ }
189
+ for _ , prefix := range []string {"./" , ".\\ " } {
190
+ if strings .HasPrefix (p , prefix ) {
191
+ return filepath .Join (fs .baseDir , strings .TrimPrefix (p , prefix ))
192
+ }
193
+ }
194
+ return p
195
+ }
196
+
158
197
func (fs * BoundOS ) Lstat (filename string ) (os.FileInfo , error ) {
198
+ filename = fs .expandDot (filename )
159
199
filename = filepath .Clean (filename )
160
200
if ! filepath .IsAbs (filename ) {
161
201
filename = filepath .Join (fs .baseDir , filename )
@@ -167,6 +207,7 @@ func (fs *BoundOS) Lstat(filename string) (os.FileInfo, error) {
167
207
}
168
208
169
209
func (fs * BoundOS ) Readlink (link string ) (string , error ) {
210
+ link = fs .expandDot (link )
170
211
if ! filepath .IsAbs (link ) {
171
212
link = filepath .Clean (filepath .Join (fs .baseDir , link ))
172
213
}
@@ -247,7 +288,7 @@ func (fs *BoundOS) insideBaseDir(filename string) (bool, error) {
247
288
// that either filename or fs.baseDir may contain.
248
289
func (fs * BoundOS ) insideBaseDirEval (filename string ) (bool , error ) {
249
290
// "/" contains all others.
250
- if fs .baseDir == "/" {
291
+ if fs .baseDir == "/" || fs . baseDir == filename {
251
292
return true , nil
252
293
}
253
294
dir , err := filepath .EvalSymlinks (filepath .Dir (filename ))
0 commit comments