aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakob Unterwurzacher2020-08-15 16:08:16 +0200
committerJakob Unterwurzacher2020-08-15 16:08:16 +0200
commit15b0b4a5fd268b421ddc347e4417b2538a540922 (patch)
tree5969cdd448bb3c105f15fe90b6f768d4be52bd1c
parentf270135c1614843f43a9df0e68b6e3fa556b6774 (diff)
v2api/reverse: start wiring up -exclude functionality
Exclude in readdir is missing.
-rw-r--r--internal/fusefrontend_reverse/excluder.go20
-rw-r--r--internal/fusefrontend_reverse/excluder_test.go83
-rw-r--r--internal/fusefrontend_reverse/mocks_test.go32
-rw-r--r--internal/fusefrontend_reverse/root_node.go10
-rw-r--r--internal/fusefrontend_reverse/rpath.go4
5 files changed, 139 insertions, 10 deletions
diff --git a/internal/fusefrontend_reverse/excluder.go b/internal/fusefrontend_reverse/excluder.go
index 337c3d2..b6cb961 100644
--- a/internal/fusefrontend_reverse/excluder.go
+++ b/internal/fusefrontend_reverse/excluder.go
@@ -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
+ }
+ 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 nil
+ return excluder
}
// getExclusionPatters prepares a list of patterns to be excluded.
diff --git a/internal/fusefrontend_reverse/excluder_test.go b/internal/fusefrontend_reverse/excluder_test.go
new file mode 100644
index 0000000..47b430a
--- /dev/null
+++ b/internal/fusefrontend_reverse/excluder_test.go
@@ -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")
+ }
+}
diff --git a/internal/fusefrontend_reverse/mocks_test.go b/internal/fusefrontend_reverse/mocks_test.go
new file mode 100644
index 0000000..2d14c1d
--- /dev/null
+++ b/internal/fusefrontend_reverse/mocks_test.go
@@ -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
+}
diff --git a/internal/fusefrontend_reverse/root_node.go b/internal/fusefrontend_reverse/root_node.go
index 4297ecf..4346306 100644
--- a/internal/fusefrontend_reverse/root_node.go
+++ b/internal/fusefrontend_reverse/root_node.go
@@ -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)
+}
diff --git a/internal/fusefrontend_reverse/rpath.go b/internal/fusefrontend_reverse/rpath.go
index 2ac65be..1e44638 100644
--- a/internal/fusefrontend_reverse/rpath.go
+++ b/internal/fusefrontend_reverse/rpath.go
@@ -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)