main
1package billy
2
3import (
4 "errors"
5 "io"
6 "os"
7 "time"
8)
9
10var (
11 ErrReadOnly = errors.New("read-only filesystem")
12 ErrNotSupported = errors.New("feature not supported")
13 ErrCrossedBoundary = errors.New("chroot boundary crossed")
14)
15
16// Capability holds the supported features of a billy filesystem. This does
17// not mean that the capability has to be supported by the underlying storage.
18// For example, a billy filesystem may support WriteCapability but the
19// storage be mounted in read only mode.
20type Capability uint64
21
22const (
23 // WriteCapability means that the fs is writable.
24 WriteCapability Capability = 1 << iota
25 // ReadCapability means that the fs is readable.
26 ReadCapability
27 // ReadAndWriteCapability is the ability to open a file in read and write mode.
28 ReadAndWriteCapability
29 // SeekCapability means it is able to move position inside the file.
30 SeekCapability
31 // TruncateCapability means that a file can be truncated.
32 TruncateCapability
33 // LockCapability is the ability to lock a file.
34 LockCapability
35
36 // DefaultCapabilities lists all capable features supported by filesystems
37 // without Capability interface. This list should not be changed until a
38 // major version is released.
39 DefaultCapabilities Capability = WriteCapability | ReadCapability |
40 ReadAndWriteCapability | SeekCapability | TruncateCapability |
41 LockCapability
42
43 // AllCapabilities lists all capable features.
44 AllCapabilities Capability = WriteCapability | ReadCapability |
45 ReadAndWriteCapability | SeekCapability | TruncateCapability |
46 LockCapability
47)
48
49// Filesystem abstract the operations in a storage-agnostic interface.
50// Each method implementation mimics the behavior of the equivalent functions
51// at the os package from the standard library.
52type Filesystem interface {
53 Basic
54 TempFile
55 Dir
56 Symlink
57 Chroot
58}
59
60// Basic abstract the basic operations in a storage-agnostic interface as
61// an extension to the Basic interface.
62type Basic interface {
63 // Create creates the named file with mode 0666 (before umask), truncating
64 // it if it already exists. If successful, methods on the returned File can
65 // be used for I/O; the associated file descriptor has mode O_RDWR.
66 Create(filename string) (File, error)
67 // Open opens the named file for reading. If successful, methods on the
68 // returned file can be used for reading; the associated file descriptor has
69 // mode O_RDONLY.
70 Open(filename string) (File, error)
71 // OpenFile is the generalized open call; most users will use Open or Create
72 // instead. It opens the named file with specified flag (O_RDONLY etc.) and
73 // perm, (0666 etc.) if applicable. If successful, methods on the returned
74 // File can be used for I/O.
75 OpenFile(filename string, flag int, perm os.FileMode) (File, error)
76 // Stat returns a FileInfo describing the named file.
77 Stat(filename string) (os.FileInfo, error)
78 // Rename renames (moves) oldpath to newpath. If newpath already exists and
79 // is not a directory, Rename replaces it. OS-specific restrictions may
80 // apply when oldpath and newpath are in different directories.
81 Rename(oldpath, newpath string) error
82 // Remove removes the named file or directory.
83 Remove(filename string) error
84 // Join joins any number of path elements into a single path, adding a
85 // Separator if necessary. Join calls filepath.Clean on the result; in
86 // particular, all empty strings are ignored. On Windows, the result is a
87 // UNC path if and only if the first path element is a UNC path.
88 Join(elem ...string) string
89}
90
91type TempFile interface {
92 // TempFile creates a new temporary file in the directory dir with a name
93 // beginning with prefix, opens the file for reading and writing, and
94 // returns the resulting *os.File. If dir is the empty string, TempFile
95 // uses the default directory for temporary files (see os.TempDir).
96 // Multiple programs calling TempFile simultaneously will not choose the
97 // same file. The caller can use f.Name() to find the pathname of the file.
98 // It is the caller's responsibility to remove the file when no longer
99 // needed.
100 TempFile(dir, prefix string) (File, error)
101}
102
103// Dir abstract the dir related operations in a storage-agnostic interface as
104// an extension to the Basic interface.
105type Dir interface {
106 // ReadDir reads the directory named by dirname and returns a list of
107 // directory entries sorted by filename.
108 ReadDir(path string) ([]os.FileInfo, error)
109 // MkdirAll creates a directory named path, along with any necessary
110 // parents, and returns nil, or else returns an error. The permission bits
111 // perm are used for all directories that MkdirAll creates. If path is/
112 // already a directory, MkdirAll does nothing and returns nil.
113 MkdirAll(filename string, perm os.FileMode) error
114}
115
116// Symlink abstract the symlink related operations in a storage-agnostic
117// interface as an extension to the Basic interface.
118type Symlink interface {
119 // Lstat returns a FileInfo describing the named file. If the file is a
120 // symbolic link, the returned FileInfo describes the symbolic link. Lstat
121 // makes no attempt to follow the link.
122 Lstat(filename string) (os.FileInfo, error)
123 // Symlink creates a symbolic-link from link to target. target may be an
124 // absolute or relative path, and need not refer to an existing node.
125 // Parent directories of link are created as necessary.
126 Symlink(target, link string) error
127 // Readlink returns the target path of link.
128 Readlink(link string) (string, error)
129}
130
131// Change abstract the FileInfo change related operations in a storage-agnostic
132// interface as an extension to the Basic interface
133type Change interface {
134 // Chmod changes the mode of the named file to mode. If the file is a
135 // symbolic link, it changes the mode of the link's target.
136 Chmod(name string, mode os.FileMode) error
137 // Lchown changes the numeric uid and gid of the named file. If the file is
138 // a symbolic link, it changes the uid and gid of the link itself.
139 Lchown(name string, uid, gid int) error
140 // Chown changes the numeric uid and gid of the named file. If the file is a
141 // symbolic link, it changes the uid and gid of the link's target.
142 Chown(name string, uid, gid int) error
143 // Chtimes changes the access and modification times of the named file,
144 // similar to the Unix utime() or utimes() functions.
145 //
146 // The underlying filesystem may truncate or round the values to a less
147 // precise time unit.
148 Chtimes(name string, atime time.Time, mtime time.Time) error
149}
150
151// Chroot abstract the chroot related operations in a storage-agnostic interface
152// as an extension to the Basic interface.
153type Chroot interface {
154 // Chroot returns a new filesystem from the same type where the new root is
155 // the given path. Files outside of the designated directory tree cannot be
156 // accessed.
157 Chroot(path string) (Filesystem, error)
158 // Root returns the root path of the filesystem.
159 Root() string
160}
161
162// File represent a file, being a subset of the os.File
163type File interface {
164 // Name returns the name of the file as presented to Open.
165 Name() string
166 io.Writer
167 // TODO: Add io.WriterAt for v6
168 // io.WriterAt
169 io.Reader
170 io.ReaderAt
171 io.Seeker
172 io.Closer
173 // Lock locks the file like e.g. flock. It protects against access from
174 // other processes.
175 Lock() error
176 // Unlock unlocks the file.
177 Unlock() error
178 // Truncate the file.
179 Truncate(size int64) error
180}
181
182// Capable interface can return the available features of a filesystem.
183type Capable interface {
184 // Capabilities returns the capabilities of a filesystem in bit flags.
185 Capabilities() Capability
186}
187
188// Capabilities returns the features supported by a filesystem. If the FS
189// does not implement Capable interface it returns all features.
190func Capabilities(fs Basic) Capability {
191 capable, ok := fs.(Capable)
192 if !ok {
193 return DefaultCapabilities
194 }
195
196 return capable.Capabilities()
197}
198
199// CapabilityCheck tests the filesystem for the provided capabilities and
200// returns true in case it supports all of them.
201func CapabilityCheck(fs Basic, capabilities Capability) bool {
202 fsCaps := Capabilities(fs)
203 return fsCaps&capabilities == capabilities
204}