Skip to content

Commit a22d183

Browse files
committed
Add Capability function to query fs capabilities
This adds the Capable interface that can be implemented in filesystems to return the features suported by it. This first iteration has the following capablities: * CapWrite * CapRead * CapReadAndWrite * CapSeek * CapTruncate * CapLock `billy.Capablilities(fs)` can be used to query a fs. The capabilities are implemented as bit flags. If a filesystem does not implement Capable interface then all capabilities will be returned as fall back. Signed-off-by: Javi Fontan <[email protected]>
1 parent df05387 commit a22d183

File tree

8 files changed

+89
-2
lines changed

8 files changed

+89
-2
lines changed

fs.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,28 @@ var (
1313
ErrCrossedBoundary = errors.New("chroot boundary crossed")
1414
)
1515

16+
// Capability holds the supported features of a filesystem.
17+
type Capability uint64
18+
19+
const (
20+
// CapWrite means that the fs is writable.
21+
CapWrite Capability = 1 << iota
22+
// CapRead means that the fs is readable.
23+
CapRead
24+
// CapReadAndWrite is the ability to open a file in read and write mode.
25+
CapReadAndWrite
26+
// CapSeek means it is able to move position inside the file.
27+
CapSeek
28+
// CapTruncate means that a file can be truncated.
29+
CapTruncate
30+
// CapLock is the ability to lock a file.
31+
CapLock
32+
33+
// CapAll lists all capable features.
34+
CapAll Capability = CapWrite | CapRead | CapReadAndWrite |
35+
CapSeek | CapTruncate | CapLock
36+
)
37+
1638
// Filesystem abstract the operations in a storage-agnostic interface.
1739
// Each method implementation mimics the behavior of the equivalent functions
1840
// at the os package from the standard library.
@@ -143,3 +165,20 @@ type File interface {
143165
// Truncate the file.
144166
Truncate(size int64) error
145167
}
168+
169+
// Capable interface can return the available features of a filesystem.
170+
type Capable interface {
171+
// Capabilities returns the capabilities of a filesystem in bit flags.
172+
Capabilities() Capability
173+
}
174+
175+
// Capabilities returns the features supported by a filesystem. If the FS
176+
// does not implement Capable interface it returns all features.
177+
func Capabilities(fs Basic) Capability {
178+
capable, ok := fs.(Capable)
179+
if !ok {
180+
return CapAll
181+
}
182+
183+
return capable.Capabilities()
184+
}

helper/chroot/chroot.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,11 @@ func (fs *ChrootHelper) Underlying() billy.Basic {
217217
return fs.underlying
218218
}
219219

220+
// Capabilities implements the Capable interface.
221+
func (fs *ChrootHelper) Capabilities() billy.Capability {
222+
return billy.Capabilities(fs.underlying)
223+
}
224+
220225
type file struct {
221226
billy.File
222227
name string

helper/mount/mount.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,11 @@ func (h *Mount) Underlying() billy.Basic {
167167
return h.underlying
168168
}
169169

170+
// Capabilities implements the Capable interface.
171+
func (fs *Mount) Capabilities() billy.Capability {
172+
return billy.Capabilities(fs.underlying)
173+
}
174+
170175
func (fs *Mount) getBasicAndPath(path string) (billy.Basic, string) {
171176
path = cleanPath(path)
172177
if !fs.isMountpoint(path) {

helper/polyfill/polyfill.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,8 @@ func (h *Polyfill) Root() string {
9898
func (h *Polyfill) Underlying() billy.Basic {
9999
return h.Basic
100100
}
101+
102+
// Capabilities implements the Capable interface.
103+
func (h *Polyfill) Capabilities() billy.Capability {
104+
return billy.Capabilities(h.Basic)
105+
}

memfs/memory.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,15 @@ func (fs *Memory) Readlink(link string) (string, error) {
190190
return string(f.content.bytes), nil
191191
}
192192

193+
// Capabilities implements the Capable interface.
194+
func (fs *Memory) Capabilities() billy.Capability {
195+
return billy.CapWrite |
196+
billy.CapRead |
197+
billy.CapReadAndWrite |
198+
billy.CapSeek |
199+
billy.CapTruncate
200+
}
201+
193202
type file struct {
194203
name string
195204
content *content
@@ -273,7 +282,7 @@ func (f *file) Close() error {
273282
func (f *file) Truncate(size int64) error {
274283
if size < int64(len(f.content.bytes)) {
275284
f.content.bytes = f.content.bytes[:size]
276-
} else if more := int(size)-len(f.content.bytes); more > 0 {
285+
} else if more := int(size) - len(f.content.bytes); more > 0 {
277286
f.content.bytes = append(f.content.bytes, make([]byte, more)...)
278287
}
279288

memfs/memory_test.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package memfs
33
import (
44
"testing"
55

6+
"gopkg.in/src-d/go-billy.v4"
67
"gopkg.in/src-d/go-billy.v4/test"
78

89
. "gopkg.in/check.v1"
@@ -20,3 +21,11 @@ var _ = Suite(&MemorySuite{})
2021
func (s *MemorySuite) SetUpTest(c *C) {
2122
s.FilesystemSuite = test.NewFilesystemSuite(New())
2223
}
24+
25+
func (s *MemorySuite) TestCapabilities(c *C) {
26+
_, ok := s.FS.(billy.Capable)
27+
c.Assert(ok, Equals, true)
28+
29+
caps := billy.Capabilities(s.FS)
30+
c.Assert(caps, Equals, billy.CapAll&^billy.CapLock)
31+
}

osfs/os.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,11 @@ func (fs *OS) Readlink(link string) (string, error) {
127127
return os.Readlink(link)
128128
}
129129

130+
// Capabilities implements the Capable interface.
131+
func (fs *OS) Capabilities() billy.Capability {
132+
return billy.CapAll
133+
}
134+
130135
// file is a wrapper for an os.File which adds support for file locking.
131136
type file struct {
132137
*os.File

osfs/os_test.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ import (
66
"path/filepath"
77
"testing"
88

9-
. "gopkg.in/check.v1"
9+
"gopkg.in/src-d/go-billy.v4"
1010
"gopkg.in/src-d/go-billy.v4/test"
11+
12+
. "gopkg.in/check.v1"
1113
)
1214

1315
func Test(t *testing.T) { TestingT(t) }
@@ -36,3 +38,11 @@ func (s *OSSuite) TestOpenDoesNotCreateDir(c *C) {
3638
_, err = os.Stat(filepath.Join(s.path, "dir"))
3739
c.Assert(os.IsNotExist(err), Equals, true)
3840
}
41+
42+
func (s *OSSuite) TestCapabilities(c *C) {
43+
_, ok := s.FS.(billy.Capable)
44+
c.Assert(ok, Equals, true)
45+
46+
caps := billy.Capabilities(s.FS)
47+
c.Assert(caps, Equals, billy.CapAll)
48+
}

0 commit comments

Comments
 (0)