aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakob Unterwurzacher2018-08-11 23:26:49 +0200
committerJakob Unterwurzacher2018-08-11 23:26:49 +0200
commitec2fdc19cf9358ae7ba09c528a5807b6b0760f9b (patch)
tree1a9a26d9f70ac26f3df2c44a6e5ed6ff9108ab76
parenteaa5aecd422bc4f6b01b6257383521ad512e08f7 (diff)
reverse mode: add --exclude option
https://github.com/rfjakob/gocryptfs/issues/235
-rw-r--r--Documentation/MANPAGE.md8
-rw-r--r--README.md1
-rw-r--r--cli_args.go5
-rw-r--r--internal/exitcodes/exitcodes.go2
-rw-r--r--internal/fusefrontend/args.go2
-rw-r--r--internal/fusefrontend/fs.go3
-rw-r--r--internal/fusefrontend_reverse/rfile.go6
-rw-r--r--internal/fusefrontend_reverse/rfs.go74
-rw-r--r--main.go5
-rw-r--r--mount.go1
-rw-r--r--tests/cli/cli_test.go11
-rw-r--r--tests/reverse/exclude_test.go104
-rw-r--r--tests/reverse/exclude_test_fs/.gocryptfs.reverse.conf21
-rw-r--r--tests/reverse/exclude_test_fs/.gocryptfs.reverse.conf.plaintextnames18
-rw-r--r--tests/reverse/exclude_test_fs/dir1/file10
-rw-r--r--tests/reverse/exclude_test_fs/dir1/file20
-rw-r--r--tests/reverse/exclude_test_fs/dir1/longfile1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx0
-rw-r--r--tests/reverse/exclude_test_fs/dir1/longfile2xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx0
-rw-r--r--tests/reverse/exclude_test_fs/dir2/file0
-rw-r--r--tests/reverse/exclude_test_fs/dir2/longdir1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/file0
-rw-r--r--tests/reverse/exclude_test_fs/dir2/longfile.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx0
-rw-r--r--tests/reverse/exclude_test_fs/dir2/subdir/file0
-rw-r--r--tests/reverse/exclude_test_fs/file10
-rw-r--r--tests/reverse/exclude_test_fs/file20
-rw-r--r--tests/reverse/exclude_test_fs/longdir1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/file0
-rw-r--r--tests/reverse/exclude_test_fs/longdir2xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/file0
-rw-r--r--tests/reverse/exclude_test_fs/longfile1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx0
-rw-r--r--tests/reverse/exclude_test_fs/longfile2xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx0
28 files changed, 258 insertions, 3 deletions
diff --git a/Documentation/MANPAGE.md b/Documentation/MANPAGE.md
index a9afac0..62e0dee 100644
--- a/Documentation/MANPAGE.md
+++ b/Documentation/MANPAGE.md
@@ -70,12 +70,18 @@ Enable (`-dev`) or disable (`-nodev`) device files in a gocryptfs mount
You need root permissions to use `-dev`.
#### -devrandom
-Use /dev/random for generating the master key instead of the default Go
+Use `/dev/random` for generating the master key instead of the default Go
implementation. This is especially useful on embedded systems with Go versions
prior to 1.9, which fall back to weak random data when the getrandom syscall
is blocking. Using this option can block indefinitely when the kernel cannot
harvest enough entropy.
+#### -exclude PATH
+Only for reverse mode: exclude relative plaintext path from the encrypted
+view. Can be passed multiple times. Example:
+
+ gocryptfs -reverse -exclude Music -exclude Movies /home/user /mnt/user.encrypted
+
#### -exec, -noexec
Enable (`-exec`) or disable (`-noexec`) executables in a gocryptfs mount
(default: `-exec`). If both are specified, `-noexec` takes precedence.
diff --git a/README.md b/README.md
index a436fff..e8f7fea 100644
--- a/README.md
+++ b/README.md
@@ -155,6 +155,7 @@ Changelog
vNEXT, in progress
* Fall back to buffered IO even when passed `O_DIRECT`
([commit](https://github.com/rfjakob/gocryptfs/commit/893e41149ed353f355047003b89eeff456990e76))
+* Add `-exclude` option for reverse mode
v1.5, 2018-06-12
* **Support extended attributes (xattr)** in forward mode
diff --git a/cli_args.go b/cli_args.go
index 1314ed7..ecbfa3a 100644
--- a/cli_args.go
+++ b/cli_args.go
@@ -27,6 +27,8 @@ type argContainer struct {
dev, nodev, suid, nosuid, exec, noexec, rw, ro bool
masterkey, mountpoint, cipherdir, cpuprofile, extpass,
memprofile, ko, passfile, ctlsock, fsname, force_owner, trace string
+ // For reverse mode, --exclude is available. It can be specified multiple times.
+ exclude multipleStrings
// Configuration file name override
config string
notifypid, scryptn int
@@ -173,6 +175,9 @@ func parseCliOpts() (args argContainer) {
flagSet.StringVar(&args.fsname, "fsname", "", "Override the filesystem name")
flagSet.StringVar(&args.force_owner, "force_owner", "", "uid:gid pair to coerce ownership")
flagSet.StringVar(&args.trace, "trace", "", "Write execution trace to file")
+
+ flagSet.Var(&args.exclude, "exclude", "Exclude relative path from reverse view")
+
flagSet.IntVar(&args.notifypid, "notifypid", 0, "Send USR1 to the specified process after "+
"successful mount - used internally for daemonization")
flagSet.IntVar(&args.scryptn, "scryptn", configfile.ScryptDefaultLogN, "scrypt cost parameter logN. Possible values: 10-28. "+
diff --git a/internal/exitcodes/exitcodes.go b/internal/exitcodes/exitcodes.go
index 3fbfdc6..b8173c7 100644
--- a/internal/exitcodes/exitcodes.go
+++ b/internal/exitcodes/exitcodes.go
@@ -68,6 +68,8 @@ const (
// TrezorError - an error was encountered while interacting with a Trezor
// device
TrezorError = 28
+ // ExcludeError - an error occoured while processing "-exclude"
+ ExcludeError = 29
)
// Err wraps an error with an associated numeric exit code
diff --git a/internal/fusefrontend/args.go b/internal/fusefrontend/args.go
index 8a64e99..5fb72cd 100644
--- a/internal/fusefrontend/args.go
+++ b/internal/fusefrontend/args.go
@@ -30,4 +30,6 @@ type Args struct {
SerializeReads bool
// Force decode even if integrity check fails (openSSL only)
ForceDecode bool
+ // Exclude is a list of paths to make inaccessible
+ Exclude []string
}
diff --git a/internal/fusefrontend/fs.go b/internal/fusefrontend/fs.go
index 23f5513..45b5b40 100644
--- a/internal/fusefrontend/fs.go
+++ b/internal/fusefrontend/fs.go
@@ -56,6 +56,9 @@ func NewFS(args Args, c *contentenc.ContentEnc, n *nametransform.NameTransform)
if args.SerializeReads {
serialize_reads.InitSerializer()
}
+ if len(args.Exclude) > 0 {
+ tlog.Warn.Printf("Forward mode does not support -exclude")
+ }
return &FS{
FileSystem: pathfs.NewLoopbackFileSystem(args.Cipherdir),
args: args,
diff --git a/internal/fusefrontend_reverse/rfile.go b/internal/fusefrontend_reverse/rfile.go
index 26756a3..7df0906 100644
--- a/internal/fusefrontend_reverse/rfile.go
+++ b/internal/fusefrontend_reverse/rfile.go
@@ -36,6 +36,12 @@ var inodeTable syncmap.Map
// newFile decrypts and opens the path "relPath" and returns a reverseFile
// object. The backing file descriptor is always read-only.
func (rfs *ReverseFS) newFile(relPath string) (*reverseFile, fuse.Status) {
+ if rfs.isExcluded(relPath) {
+ // Excluded paths should have been filtered out beforehand. Better safe
+ // than sorry.
+ tlog.Warn.Printf("BUG: newFile: received excluded path %q. This should not happen.", relPath)
+ return nil, fuse.ENOENT
+ }
pRelPath, err := rfs.decryptPath(relPath)
if err != nil {
return nil, fuse.ToStatus(err)
diff --git a/internal/fusefrontend_reverse/rfs.go b/internal/fusefrontend_reverse/rfs.go
index 829983b..ba8810c 100644
--- a/internal/fusefrontend_reverse/rfs.go
+++ b/internal/fusefrontend_reverse/rfs.go
@@ -2,7 +2,9 @@ package fusefrontend_reverse
import (
"fmt"
+ "os"
"path/filepath"
+ "strings"
"syscall"
"golang.org/x/sys/unix"
@@ -14,6 +16,8 @@ import (
"github.com/rfjakob/gocryptfs/internal/configfile"
"github.com/rfjakob/gocryptfs/internal/contentenc"
"github.com/rfjakob/gocryptfs/internal/cryptocore"
+ "github.com/rfjakob/gocryptfs/internal/ctlsock"
+ "github.com/rfjakob/gocryptfs/internal/exitcodes"
"github.com/rfjakob/gocryptfs/internal/fusefrontend"
"github.com/rfjakob/gocryptfs/internal/nametransform"
"github.com/rfjakob/gocryptfs/internal/pathiv"
@@ -34,6 +38,8 @@ type ReverseFS struct {
nameTransform *nametransform.NameTransform
// Content encryption helper
contentEnc *contentenc.ContentEnc
+ // Relative ciphertext paths to exclude (hide) from the user. Used by -exclude.
+ cExclude []string
}
var _ pathfs.FileSystem = &ReverseFS{}
@@ -43,7 +49,7 @@ var _ pathfs.FileSystem = &ReverseFS{}
// ReverseFS provides an encrypted view.
func NewFS(args fusefrontend.Args, c *contentenc.ContentEnc, n *nametransform.NameTransform) *ReverseFS {
initLongnameCache()
- return &ReverseFS{
+ fs := &ReverseFS{
// pathfs.defaultFileSystem returns ENOSYS for all operations
FileSystem: pathfs.NewDefaultFileSystem(),
loopbackfs: pathfs.NewLoopbackFileSystem(args.Cipherdir),
@@ -51,6 +57,22 @@ func NewFS(args fusefrontend.Args, c *contentenc.ContentEnc, n *nametransform.Na
nameTransform: n,
contentEnc: c,
}
+ if len(args.Exclude) > 0 {
+ for _, dirty := range args.Exclude {
+ clean := ctlsock.SanitizePath(dirty)
+ if clean != dirty {
+ tlog.Warn.Printf("-exclude: non-canonical path %q has been interpreted as %q", dirty, clean)
+ }
+ cPath, err := fs.EncryptPath(clean)
+ if err != nil {
+ tlog.Fatal.Printf("-exclude: EncryptPath %q failed: %v", clean, err)
+ os.Exit(exitcodes.ExcludeError)
+ }
+ fs.cExclude = append(fs.cExclude, cPath)
+ }
+ tlog.Debug.Printf("-exclude: %v -> %v", fs.args.Exclude, fs.cExclude)
+ }
+ return fs
}
// relDir is identical to filepath.Dir excepts that it returns "" when
@@ -64,6 +86,21 @@ func relDir(path string) string {
return dir
}
+// isExcluded finds out if relative ciphertext path "relPath" is excluded
+// (used when -exclude is passed by the user)
+func (rfs *ReverseFS) isExcluded(relPath string) bool {
+ for _, e := range rfs.cExclude {
+ if e == relPath {
+ return true
+ }
+ // Files inside an excluded directory are also excluded
+ if strings.HasPrefix(relPath, e+"/") {
+ return true
+ }
+ }
+ return false
+}
+
// isDirIV determines if the path points to a gocryptfs.diriv file
func (rfs *ReverseFS) isDirIV(relPath string) bool {
if rfs.args.PlaintextNames {
@@ -99,6 +136,9 @@ func (rfs *ReverseFS) isTranslatedConfig(relPath string) bool {
// GetAttr - FUSE call
// "relPath" is the relative ciphertext path
func (rfs *ReverseFS) GetAttr(relPath string, context *fuse.Context) (*fuse.Attr, fuse.Status) {
+ if rfs.isExcluded(relPath) {
+ return nil, fuse.ENOENT
+ }
// Handle "gocryptfs.conf"
if rfs.isTranslatedConfig(relPath) {
absConfPath, _ := rfs.abs(configfile.ConfReverseName, nil)
@@ -180,6 +220,9 @@ func (rfs *ReverseFS) GetAttr(relPath string, context *fuse.Context) (*fuse.Attr
// Access - FUSE call
func (rfs *ReverseFS) Access(relPath string, mode uint32, context *fuse.Context) fuse.Status {
+ if rfs.isExcluded(relPath) {
+ return fuse.ENOENT
+ }
if rfs.isTranslatedConfig(relPath) || rfs.isDirIV(relPath) || rfs.isNameFile(relPath) {
// access(2) R_OK flag for checking if the file is readable, always 4 as defined in POSIX.
ROK := uint32(0x4)
@@ -203,6 +246,9 @@ func (rfs *ReverseFS) Access(relPath string, mode uint32, context *fuse.Context)
// Open - FUSE call
func (rfs *ReverseFS) Open(relPath string, flags uint32, context *fuse.Context) (fuseFile nodefs.File, status fuse.Status) {
+ if rfs.isExcluded(relPath) {
+ return nil, fuse.ENOENT
+ }
if rfs.isTranslatedConfig(relPath) {
return rfs.loopbackfs.Open(configfile.ConfReverseName, flags, context)
}
@@ -242,6 +288,9 @@ func (rfs *ReverseFS) openDirPlaintextnames(relPath string, entries []fuse.DirEn
// OpenDir - FUSE readdir call
func (rfs *ReverseFS) OpenDir(cipherPath string, context *fuse.Context) ([]fuse.DirEntry, fuse.Status) {
+ if rfs.isExcluded(cipherPath) {
+ return nil, fuse.ENOENT
+ }
relPath, err := rfs.decryptPath(cipherPath)
if err != nil {
return nil, fuse.ToStatus(err)
@@ -292,6 +341,21 @@ func (rfs *ReverseFS) OpenDir(cipherPath string, context *fuse.Context) ([]fuse.
}
entries[i].Name = cName
}
+ // Filter out excluded entries
+ if rfs.cExclude != nil {
+ filtered := make([]fuse.DirEntry, 0, len(entries))
+ for _, entry := range entries {
+ // filepath.Join handles the case of cipherPath="" correctly:
+ // Join("", "foo") -> "foo". This does not: cipherPath + "/" + name"
+ p := filepath.Join(cipherPath, entry.Name)
+ if rfs.isExcluded(p) {
+ // Skip file
+ continue
+ }
+ filtered = append(filtered, entry)
+ }
+ entries = filtered
+ }
entries = append(entries, virtualFiles[:nVirtual]...)
return entries, fuse.OK
}
@@ -301,7 +365,10 @@ func (rfs *ReverseFS) OpenDir(cipherPath string, context *fuse.Context) ([]fuse.
// Securing statfs against symlink races seems to be more trouble than
// it's worth, so we just ignore the path and always return info about the
// backing storage root dir.
-func (rfs *ReverseFS) StatFs(path string) *fuse.StatfsOut {
+func (rfs *ReverseFS) StatFs(relPath string) *fuse.StatfsOut {
+ if rfs.isExcluded(relPath) {
+ return nil
+ }
var s syscall.Statfs_t
err := syscall.Statfs(rfs.args.Cipherdir, &s)
if err != nil {
@@ -314,6 +381,9 @@ func (rfs *ReverseFS) StatFs(path string) *fuse.StatfsOut {
// Readlink - FUSE call
func (rfs *ReverseFS) Readlink(relPath string, context *fuse.Context) (string, fuse.Status) {
+ if rfs.isExcluded(relPath) {
+ return "", fuse.ENOENT
+ }
dirfd, name, err := rfs.openBackingDir(relPath)
if err != nil {
return "", fuse.ToStatus(err)
diff --git a/main.go b/main.go
index 24f16bd..f423cd1 100644
--- a/main.go
+++ b/main.go
@@ -212,6 +212,11 @@ func main() {
// "-reverse" implies "-aessiv"
if args.reverse {
args.aessiv = true
+ } else {
+ if args.exclude != nil {
+ tlog.Fatal.Printf("-exclude only works in reverse mode")
+ os.Exit(exitcodes.ExcludeError)
+ }
}
// "-config"
if args.config != "" {
diff --git a/mount.go b/mount.go
index a673848..e9714d4 100644
--- a/mount.go
+++ b/mount.go
@@ -196,6 +196,7 @@ func initFuseFrontend(args *argContainer) (pfs pathfs.FileSystem, wipeKeys func(
SerializeReads: args.serialize_reads,
ForceDecode: args.forcedecode,
ForceOwner: args._forceOwner,
+ Exclude: args.exclude,
}
// confFile is nil when "-zerokey" or "-masterkey" was used
if confFile != nil {
diff --git a/tests/cli/cli_test.go b/tests/cli/cli_test.go
index 5b78359..3b53181 100644
--- a/tests/cli/cli_test.go
+++ b/tests/cli/cli_test.go
@@ -484,3 +484,14 @@ func TestMissingOArg(t *testing.T) {
exitcodes.Usage, exitCode)
}
}
+
+// -exclude must return an error in forward mode
+func TestExcludeForward(t *testing.T) {
+ dir := test_helpers.InitFS(t)
+ mnt := dir + ".mnt"
+ err := test_helpers.Mount(dir, mnt, false, "-extpass", "echo test", "-exclude", "foo")
+ if err == nil {
+ t.Errorf("-exclude in forward mode should fail")
+ }
+ t.Log(err)
+}
diff --git a/tests/reverse/exclude_test.go b/tests/reverse/exclude_test.go
new file mode 100644
index 0000000..a64b3da
--- /dev/null
+++ b/tests/reverse/exclude_test.go
@@ -0,0 +1,104 @@
+package reverse_test
+
+import (
+ "io/ioutil"
+ "testing"
+
+ "github.com/rfjakob/gocryptfs/internal/ctlsock"
+ "github.com/rfjakob/gocryptfs/tests/test_helpers"
+)
+
+const xxx = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+
+/*
+tree exclude_test_fs
+exclude_test_fs/
+├── dir1
+│ ├── file1
+│ ├── file2
+│ ├── longfile1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+│ └── longfile2xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+├── dir2
+│ ├── file
+│ ├── longdir1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+│ │ └── file
+│ ├── longfile.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+│ └── subdir
+│ └── file
+├── file1
+├── file2
+├── longdir1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+│ └── file
+├── longdir2xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+│ └── file
+├── longfile1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+└── longfile2xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+*/
+
+func ctlsockEncryptPath(t *testing.T, sock string, path string) string {
+ req := ctlsock.RequestStruct{EncryptPath: path}
+ response := test_helpers.QueryCtlSock(t, sock, req)
+ if response.ErrNo != 0 {
+ t.Fatal(response)
+ }
+ return response.Result
+}
+
+func TestExclude(t *testing.T) {
+ pOk := []string{
+ "file2",
+ "dir1/file1",
+ "dir1/longfile1" + xxx,
+ "longdir1" + xxx,
+ "longdir1" + xxx + "/file",
+ "longfile1" + xxx,
+ }
+ pExclude := []string{
+ "file1",
+ "dir1/file2",
+ "dir1/longfile2" + xxx,
+ "dir2",
+ "dir2/file",
+ "dir2/file/xxx",
+ "dir2/subdir",
+ "dir2/subdir/file",
+ "dir2/longdir1" + xxx + "/file",
+ "dir2/longfile." + xxx,
+ "longfile2" + xxx,
+ }
+ // Mount reverse fs
+ mnt, err := ioutil.TempDir(test_helpers.TmpDir, "TestExclude")
+ if err != nil {
+ t.Fatal(err)
+ }
+ sock := mnt + ".sock"
+ cliArgs := []string{"-reverse", "-extpass", "echo test", "-ctlsock", sock}
+ for _, v := range pExclude {
+ cliArgs = append(cliArgs, "-exclude", v)
+ }
+ if plaintextnames {
+ cliArgs = append(cliArgs, "-config", "exclude_test_fs/.gocryptfs.reverse.conf.plaintextnames")
+ }
+ test_helpers.MountOrFatal(t, "exclude_test_fs", mnt, cliArgs...)
+ defer test_helpers.UnmountPanic(mnt)
+ // Get encrypted version of "ok" and "excluded" paths
+ cOk := make([]string, len(pOk))
+ cExclude := make([]string, len(pExclude))
+ for i, v := range pOk {
+ cOk[i] = ctlsockEncryptPath(t, sock, v)
+ }
+ for i, v := range pExclude {
+ cExclude[i] = ctlsockEncryptPath(t, sock, v)
+ }
+ // Check that "excluded" paths are not there and "ok" paths are there
+ for i, v := range cExclude {
+ if test_helpers.VerifyExistence(mnt + "/" + v) {
+ t.Errorf("File %q / %q is visible, but should be excluded", pExclude[i], v)
+ }
+ }
+ for i, v := range cOk {
+ if !test_helpers.VerifyExistence(mnt + "/" + v) {
+ t.Errorf("File %q / %q is hidden, but should be visible", pOk[i], v)
+ }
+ }
+}
diff --git a/tests/reverse/exclude_test_fs/.gocryptfs.reverse.conf b/tests/reverse/exclude_test_fs/.gocryptfs.reverse.conf
new file mode 100644
index 0000000..835d11c
--- /dev/null
+++ b/tests/reverse/exclude_test_fs/.gocryptfs.reverse.conf
@@ -0,0 +1,21 @@
+{
+ "Creator": "gocryptfs v1.5-41-gf48b731-dirty",
+ "EncryptedKey": "FkACqloUeFZesem0UzRD3ezLXtPl8wIAxEHoIEfZxFdLMQeWOxqtw5xopJagDWE/GI1VFSUIrJIIIwwgMipmYA==",
+ "ScryptObject": {
+ "Salt": "UVfIgV31uj/voHWI4GqGwsTcbVKyYDOWvbleqJKhZbk=",
+ "N": 1024,
+ "R": 8,
+ "P": 1,
+ "KeyLen": 32
+ },
+ "Version": 2,
+ "FeatureFlags": [
+ "GCMIV128",
+ "HKDF",
+ "DirIV",
+ "EMENames",
+ "LongNames",
+ "Raw64",
+ "AESSIV"
+ ]
+}
diff --git a/tests/reverse/exclude_test_fs/.gocryptfs.reverse.conf.plaintextnames b/tests/reverse/exclude_test_fs/.gocryptfs.reverse.conf.plaintextnames
new file mode 100644
index 0000000..9cb762c
--- /dev/null
+++ b/tests/reverse/exclude_test_fs/.gocryptfs.reverse.conf.plaintextnames
@@ -0,0 +1,18 @@
+{
+ "Creator": "gocryptfs v1.5-41-gf48b731-dirty",
+ "EncryptedKey": "wAmckZb7QsIv/GCdkhb5ep8TwJa44qhnswn5tbER6Tifk8TbUmkwBTceaTtYfHAnTQ48q9mnIlcN9cfbNe5oPw==",
+ "ScryptObject": {
+ "Salt": "o5XJ78TgG85zZXRnU55ZqHhKLbPge6jsyDiqrLvSqe0=",
+ "N": 1024,
+ "R": 8,
+ "P": 1,
+ "KeyLen": 32
+ },
+ "Version": 2,
+ "FeatureFlags": [
+ "GCMIV128",
+ "HKDF",
+ "PlaintextNames",
+ "AESSIV"
+ ]
+}
diff --git a/tests/reverse/exclude_test_fs/dir1/file1 b/tests/reverse/exclude_test_fs/dir1/file1
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/reverse/exclude_test_fs/dir1/file1
diff --git a/tests/reverse/exclude_test_fs/dir1/file2 b/tests/reverse/exclude_test_fs/dir1/file2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/reverse/exclude_test_fs/dir1/file2
diff --git a/tests/reverse/exclude_test_fs/dir1/longfile1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx b/tests/reverse/exclude_test_fs/dir1/longfile1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/reverse/exclude_test_fs/dir1/longfile1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
diff --git a/tests/reverse/exclude_test_fs/dir1/longfile2xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx b/tests/reverse/exclude_test_fs/dir1/longfile2xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/reverse/exclude_test_fs/dir1/longfile2xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
diff --git a/tests/reverse/exclude_test_fs/dir2/file b/tests/reverse/exclude_test_fs/dir2/file
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/reverse/exclude_test_fs/dir2/file
diff --git a/tests/reverse/exclude_test_fs/dir2/longdir1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/file b/tests/reverse/exclude_test_fs/dir2/longdir1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/file
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/reverse/exclude_test_fs/dir2/longdir1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/file
diff --git a/tests/reverse/exclude_test_fs/dir2/longfile.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx b/tests/reverse/exclude_test_fs/dir2/longfile.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/reverse/exclude_test_fs/dir2/longfile.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
diff --git a/tests/reverse/exclude_test_fs/dir2/subdir/file b/tests/reverse/exclude_test_fs/dir2/subdir/file
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/reverse/exclude_test_fs/dir2/subdir/file
diff --git a/tests/reverse/exclude_test_fs/file1 b/tests/reverse/exclude_test_fs/file1
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/reverse/exclude_test_fs/file1
diff --git a/tests/reverse/exclude_test_fs/file2 b/tests/reverse/exclude_test_fs/file2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/reverse/exclude_test_fs/file2
diff --git a/tests/reverse/exclude_test_fs/longdir1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/file b/tests/reverse/exclude_test_fs/longdir1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/file
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/reverse/exclude_test_fs/longdir1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/file
diff --git a/tests/reverse/exclude_test_fs/longdir2xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/file b/tests/reverse/exclude_test_fs/longdir2xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/file
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/reverse/exclude_test_fs/longdir2xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/file
diff --git a/tests/reverse/exclude_test_fs/longfile1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx b/tests/reverse/exclude_test_fs/longfile1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/reverse/exclude_test_fs/longfile1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
diff --git a/tests/reverse/exclude_test_fs/longfile2xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx b/tests/reverse/exclude_test_fs/longfile2xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/reverse/exclude_test_fs/longfile2xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx