Skip to content

Commit 3994cd7

Browse files
committed
osfs: Add WithDeduplicatePath
In specific workflows within the BoundOS OS type, the returned path may have the base dir duplicated. By default such duplications are removed automatically, the new WithDeduplicatePath allows users to toggle that behaviour. Signed-off-by: Paulo Gomes <[email protected]>
1 parent e223a66 commit 3994cd7

File tree

3 files changed

+110
-66
lines changed

3 files changed

+110
-66
lines changed

osfs/os.go

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,18 @@ const (
2222
var Default = &ChrootOS{}
2323

2424
// New returns a new OS filesystem.
25+
// By default paths are deduplicated, but still enforced
26+
// under baseDir. For more info refer to WithDeduplicatePath.
2527
func New(baseDir string, opts ...Option) billy.Filesystem {
26-
o := &options{}
28+
o := &options{
29+
deduplicatePath: true,
30+
}
2731
for _, opt := range opts {
2832
opt(o)
2933
}
3034

3135
if o.Type == BoundOSFS {
32-
return newBoundOS(baseDir)
36+
return newBoundOS(baseDir, o.deduplicatePath)
3337
}
3438

3539
return newChrootOS(baseDir)
@@ -49,8 +53,23 @@ func WithChrootOS() Option {
4953
}
5054
}
5155

56+
// WithDeduplicatePath toggles the deduplication of the base dir in the path.
57+
// This occurs when absolute links are being used.
58+
// Assuming base dir /base/dir and an absolute symlink /base/dir/target:
59+
//
60+
// With DeduplicatePath (default): /base/dir/target
61+
// Without DeduplicatePath: /base/dir/base/dir/target
62+
//
63+
// This option is only used by the BoundOS OS type.
64+
func WithDeduplicatePath(enabled bool) Option {
65+
return func(o *options) {
66+
o.deduplicatePath = enabled
67+
}
68+
}
69+
5270
type options struct {
5371
Type
72+
deduplicatePath bool
5473
}
5574

5675
type Type int

osfs/os_bound.go

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,12 @@ import (
4141
// 3. Readlink and Lstat ensures that the link file is located within the base
4242
// dir, evaluating any symlinks that file or base dir may contain.
4343
type BoundOS struct {
44-
baseDir string
44+
baseDir string
45+
deduplicatePath bool
4546
}
4647

47-
func newBoundOS(d string) billy.Filesystem {
48-
return &BoundOS{baseDir: d}
48+
func newBoundOS(d string, deduplicatePath bool) billy.Filesystem {
49+
return &BoundOS{baseDir: d, deduplicatePath: deduplicatePath}
4950
}
5051

5152
func (fs *BoundOS) Create(filename string) (billy.File, error) {
@@ -212,10 +213,21 @@ func (fs *BoundOS) createDir(fullpath string) error {
212213
func (fs *BoundOS) abs(filename string) (string, error) {
213214
if filename == fs.baseDir {
214215
filename = string(filepath.Separator)
215-
} else if cw := fs.baseDir + string(filepath.Separator); strings.HasPrefix(filename, cw) {
216-
filename = strings.TrimPrefix(filename, cw)
217216
}
218-
return securejoin.SecureJoin(fs.baseDir, filename)
217+
218+
path, err := securejoin.SecureJoin(fs.baseDir, filename)
219+
if err != nil {
220+
return "", nil
221+
}
222+
223+
if fs.deduplicatePath {
224+
vol := filepath.VolumeName(fs.baseDir)
225+
dup := filepath.Join(fs.baseDir, fs.baseDir[len(vol):])
226+
if strings.HasPrefix(path, dup+string(filepath.Separator)) {
227+
return fs.abs(path[len(dup):])
228+
}
229+
}
230+
return path, nil
219231
}
220232

221233
// insideBaseDir checks whether filename is located within

0 commit comments

Comments
 (0)