2020-09-27 19:24:08 +00:00
|
|
|
package filesystem
|
|
|
|
|
|
|
|
import (
|
2020-11-08 21:52:20 +00:00
|
|
|
"emperror.dev/errors"
|
|
|
|
"fmt"
|
2020-09-27 19:24:08 +00:00
|
|
|
"github.com/apex/log"
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
)
|
|
|
|
|
2020-11-08 21:52:20 +00:00
|
|
|
var ErrIsDirectory = errors.Sentinel("filesystem: is a directory")
|
|
|
|
var ErrNotEnoughDiskSpace = errors.Sentinel("filesystem: not enough disk space")
|
|
|
|
var ErrUnknownArchiveFormat = errors.Sentinel("filesystem: unknown archive format")
|
|
|
|
|
|
|
|
type BadPathResolutionError struct {
|
|
|
|
path string
|
|
|
|
resolved string
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns the specific error for a bad path resolution.
|
|
|
|
func (b *BadPathResolutionError) Error() string {
|
|
|
|
r := b.resolved
|
|
|
|
if r == "" {
|
|
|
|
r = "<empty>"
|
|
|
|
}
|
|
|
|
return fmt.Sprintf("filesystem: server path [%s] resolves to a location outside the server root: %s", b.path, r)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns a new BadPathResolution error.
|
|
|
|
func NewBadPathResolution(path string, resolved string) *BadPathResolutionError {
|
|
|
|
return &BadPathResolutionError{path, resolved}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Determines if the given error is a bad path resolution error.
|
|
|
|
func IsBadPathResolutionError(err error) bool {
|
2020-11-08 23:15:39 +00:00
|
|
|
e := errors.Unwrap(err)
|
|
|
|
if e == nil {
|
|
|
|
e = err
|
|
|
|
}
|
|
|
|
|
|
|
|
if _, ok := e.(*BadPathResolutionError); ok {
|
2020-11-08 21:52:20 +00:00
|
|
|
return true
|
|
|
|
}
|
2020-11-08 23:15:39 +00:00
|
|
|
|
2020-11-08 21:52:20 +00:00
|
|
|
return false
|
|
|
|
}
|
2020-09-27 19:24:08 +00:00
|
|
|
|
|
|
|
// Generates an error logger instance with some basic information.
|
|
|
|
func (fs *Filesystem) error(err error) *log.Entry {
|
|
|
|
return log.WithField("subsystem", "filesystem").WithField("root", fs.root).WithField("error", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handle errors encountered when walking through directories.
|
|
|
|
//
|
|
|
|
// If there is a path resolution error just skip the item entirely. Only return this for a
|
|
|
|
// directory, otherwise return nil. Returning this error for a file will stop the walking
|
|
|
|
// for the remainder of the directory. This is assuming an os.FileInfo struct was even returned.
|
|
|
|
func (fs *Filesystem) handleWalkerError(err error, f os.FileInfo) error {
|
2020-11-08 21:52:20 +00:00
|
|
|
if !IsBadPathResolutionError(err) {
|
|
|
|
return errors.WithStackIf(err)
|
2020-09-27 19:24:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if f != nil && f.IsDir() {
|
|
|
|
return filepath.SkipDir
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
2020-11-08 21:52:20 +00:00
|
|
|
}
|