v2api/reverse: start wiring up -exclude functionality

Exclude in readdir is missing.
This commit is contained in:
Jakob Unterwurzacher 2020-08-15 16:08:16 +02:00
parent f270135c16
commit 15b0b4a5fd
5 changed files with 139 additions and 10 deletions

View File

@ -15,15 +15,19 @@ import (
// prepareExcluder creates an object to check if paths are excluded
// based on the patterns specified in the command line.
func prepareExcluder(args fusefrontend.Args) *ignore.GitIgnore {
if len(args.Exclude) > 0 || len(args.ExcludeWildcard) > 0 || len(args.ExcludeFrom) > 0 {
excluder, err := ignore.CompileIgnoreLines(getExclusionPatterns(args)...)
if err != nil {
tlog.Fatal.Printf("Error compiling exclusion rules: %q", err)
os.Exit(exitcodes.ExcludeError)
}
return excluder
if len(args.Exclude) == 0 && len(args.ExcludeWildcard) == 0 && len(args.ExcludeFrom) == 0 {
return nil
}
return nil
patterns := getExclusionPatterns(args)
if len(patterns) == 0 {
panic(patterns)
}
excluder, err := ignore.CompileIgnoreLines(patterns...)
if err != nil {
tlog.Fatal.Printf("Error compiling exclusion rules: %v", err)
os.Exit(exitcodes.ExcludeError)
}
return excluder
}
// getExclusionPatters prepares a list of patterns to be excluded.

View File

@ -0,0 +1,83 @@
package fusefrontend_reverse
import (
"io/ioutil"
"os"
"reflect"
"testing"
"github.com/rfjakob/gocryptfs/internal/fusefrontend"
)
func TestShouldNoCreateExcluderIfNoPattersWereSpecified(t *testing.T) {
var args fusefrontend.Args
excluder := prepareExcluder(args)
if excluder != nil {
t.Error("Should not have created excluder")
}
}
func TestShouldPrefixExcludeValuesWithSlash(t *testing.T) {
var args fusefrontend.Args
args.Exclude = []string{"file1", "dir1/file2.txt"}
args.ExcludeWildcard = []string{"*~", "build/*.o"}
expected := []string{"/file1", "/dir1/file2.txt", "*~", "build/*.o"}
patterns := getExclusionPatterns(args)
if !reflect.DeepEqual(patterns, expected) {
t.Errorf("expected %q, got %q", expected, patterns)
}
}
func TestShouldReadExcludePatternsFromFiles(t *testing.T) {
tmpfile1, err := ioutil.TempFile("", "excludetest")
if err != nil {
t.Fatal(err)
}
exclude1 := tmpfile1.Name()
defer os.Remove(exclude1)
defer tmpfile1.Close()
tmpfile2, err := ioutil.TempFile("", "excludetest")
if err != nil {
t.Fatal(err)
}
exclude2 := tmpfile2.Name()
defer os.Remove(exclude2)
defer tmpfile2.Close()
tmpfile1.WriteString("file1.1\n")
tmpfile1.WriteString("file1.2\n")
tmpfile2.WriteString("file2.1\n")
tmpfile2.WriteString("file2.2\n")
var args fusefrontend.Args
args.ExcludeWildcard = []string{"cmdline1"}
args.ExcludeFrom = []string{exclude1, exclude2}
// An empty string is returned for the last empty line
// It's ignored when the patterns are actually compiled
expected := []string{"cmdline1", "file1.1", "file1.2", "", "file2.1", "file2.2", ""}
patterns := getExclusionPatterns(args)
if !reflect.DeepEqual(patterns, expected) {
t.Errorf("expected %q, got %q", expected, patterns)
}
}
func TestShouldReturnFalseIfThereAreNoExclusions(t *testing.T) {
var rfs RootNode
if rfs.isExcludedPlain("any/path") {
t.Error("Should not exclude any path if no exclusions were specified")
}
}
func TestShouldCallIgnoreParserToCheckExclusion(t *testing.T) {
rfs, ignorerMock := createRFSWithMocks()
rfs.isExcludedPlain("some/path")
if ignorerMock.calledWith != "some/path" {
t.Error("Failed to call IgnoreParser")
}
}

View File

@ -0,0 +1,32 @@
package fusefrontend_reverse
import (
"github.com/rfjakob/gocryptfs/internal/nametransform"
)
type IgnoreParserMock struct {
toExclude string
calledWith string
}
func (parser *IgnoreParserMock) MatchesPath(f string) bool {
parser.calledWith = f
return f == parser.toExclude
}
type NameTransformMock struct {
nametransform.NameTransform
}
func (n *NameTransformMock) DecryptName(cipherName string, iv []byte) (string, error) {
return "mockdecrypt_" + cipherName, nil
}
func createRFSWithMocks() (*RootNode, *IgnoreParserMock) {
ignorerMock := &IgnoreParserMock{}
nameTransformMock := &NameTransformMock{}
var rfs RootNode
rfs.excluder = ignorerMock
rfs.nameTransform = nameTransformMock
return &rfs, ignorerMock
}

View File

@ -27,8 +27,8 @@ type RootNode struct {
nameTransform nametransform.NameTransformer
// Content encryption helper
contentEnc *contentenc.ContentEnc
// Tests whether a path is excluded (hiden) from the user. Used by -exclude.
excluder ignore.IgnoreParser
// Tests whether a path is excluded (hidden) from the user. Used by -exclude.
excluder *ignore.GitIgnore
// inoMap translates inode numbers from different devices to unique inode
// numbers.
inoMap *inomap.InoMap
@ -78,3 +78,9 @@ func (rn *RootNode) findLongnameParent(fd int, diriv []byte, longname string) (p
}
return
}
// isExcludedPlain finds out if the plaintext path "pPath" is
// excluded (used when -exclude is passed by the user).
func (rn *RootNode) isExcludedPlain(pPath string) bool {
return rn.excluder != nil && rn.excluder.MatchesPath(pPath)
}

View File

@ -109,6 +109,10 @@ func (rn *RootNode) openBackingDir(cPath string) (dirfd int, pName string, err e
if err != nil {
return
}
if rn.isExcludedPlain(pRelPath) {
err = syscall.EPERM
return
}
// Open directory, safe against symlink races
pDir := filepath.Dir(pRelPath)
dirfd, err = syscallcompat.OpenDirNofollow(rn.args.Cipherdir, pDir)