parent
15b0b4a5fd
commit
94e8fc12ea
|
@ -2,6 +2,7 @@ package fusefrontend_reverse
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -15,12 +16,9 @@ import (
|
||||||
// prepareExcluder creates an object to check if paths are excluded
|
// prepareExcluder creates an object to check if paths are excluded
|
||||||
// based on the patterns specified in the command line.
|
// based on the patterns specified in the command line.
|
||||||
func prepareExcluder(args fusefrontend.Args) *ignore.GitIgnore {
|
func prepareExcluder(args fusefrontend.Args) *ignore.GitIgnore {
|
||||||
if len(args.Exclude) == 0 && len(args.ExcludeWildcard) == 0 && len(args.ExcludeFrom) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
patterns := getExclusionPatterns(args)
|
patterns := getExclusionPatterns(args)
|
||||||
if len(patterns) == 0 {
|
if len(patterns) == 0 {
|
||||||
panic(patterns)
|
log.Panic(patterns)
|
||||||
}
|
}
|
||||||
excluder, err := ignore.CompileIgnoreLines(patterns...)
|
excluder, err := ignore.CompileIgnoreLines(patterns...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -9,14 +9,6 @@ import (
|
||||||
"github.com/rfjakob/gocryptfs/internal/fusefrontend"
|
"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) {
|
func TestShouldPrefixExcludeValuesWithSlash(t *testing.T) {
|
||||||
var args fusefrontend.Args
|
var args fusefrontend.Args
|
||||||
args.Exclude = []string{"file1", "dir1/file2.txt"}
|
args.Exclude = []string{"file1", "dir1/file2.txt"}
|
||||||
|
|
|
@ -26,8 +26,7 @@ type Node struct {
|
||||||
|
|
||||||
// Lookup - FUSE call for discovering a file.
|
// Lookup - FUSE call for discovering a file.
|
||||||
func (n *Node) Lookup(ctx context.Context, cName string, out *fuse.EntryOut) (ch *fs.Inode, errno syscall.Errno) {
|
func (n *Node) Lookup(ctx context.Context, cName string, out *fuse.EntryOut) (ch *fs.Inode, errno syscall.Errno) {
|
||||||
dirfd := int(-1)
|
var d *dirfdPlus
|
||||||
pName := ""
|
|
||||||
t := n.lookupFileType(cName)
|
t := n.lookupFileType(cName)
|
||||||
if t == typeDiriv {
|
if t == typeDiriv {
|
||||||
// gocryptfs.diriv
|
// gocryptfs.diriv
|
||||||
|
@ -40,14 +39,15 @@ func (n *Node) Lookup(ctx context.Context, cName string, out *fuse.EntryOut) (ch
|
||||||
return n.lookupConf(ctx, out)
|
return n.lookupConf(ctx, out)
|
||||||
} else if t == typeReal {
|
} else if t == typeReal {
|
||||||
// real file
|
// real file
|
||||||
dirfd, pName, errno = n.prepareAtSyscall(cName)
|
d, errno = n.prepareAtSyscall(cName)
|
||||||
|
//fmt.Printf("Lookup: prepareAtSyscall -> d=%#v, errno=%d\n", d, errno)
|
||||||
if errno != 0 {
|
if errno != 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer syscall.Close(dirfd)
|
defer syscall.Close(d.dirfd)
|
||||||
}
|
}
|
||||||
// Get device number and inode number into `st`
|
// Get device number and inode number into `st`
|
||||||
st, err := syscallcompat.Fstatat2(dirfd, pName, unix.AT_SYMLINK_NOFOLLOW)
|
st, err := syscallcompat.Fstatat2(d.dirfd, d.pName, unix.AT_SYMLINK_NOFOLLOW)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fs.ToErrno(err)
|
return nil, fs.ToErrno(err)
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,7 @@ func (n *Node) Lookup(ctx context.Context, cName string, out *fuse.EntryOut) (ch
|
||||||
ch = n.newChild(ctx, st, out)
|
ch = n.newChild(ctx, st, out)
|
||||||
// Translate ciphertext size in `out.Attr.Size` to plaintext size
|
// Translate ciphertext size in `out.Attr.Size` to plaintext size
|
||||||
if t == typeReal {
|
if t == typeReal {
|
||||||
n.translateSize(dirfd, cName, pName, &out.Attr)
|
n.translateSize(d.dirfd, cName, d.pName, &out.Attr)
|
||||||
}
|
}
|
||||||
return ch, 0
|
return ch, 0
|
||||||
}
|
}
|
||||||
|
@ -69,13 +69,13 @@ func (n *Node) Getattr(ctx context.Context, f fs.FileHandle, out *fuse.AttrOut)
|
||||||
return f.(fs.FileGetattrer).Getattr(ctx, out)
|
return f.(fs.FileGetattrer).Getattr(ctx, out)
|
||||||
}
|
}
|
||||||
|
|
||||||
dirfd, pName, errno := n.prepareAtSyscall("")
|
d, errno := n.prepareAtSyscall("")
|
||||||
if errno != 0 {
|
if errno != 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer syscall.Close(dirfd)
|
defer syscall.Close(d.dirfd)
|
||||||
|
|
||||||
st, err := syscallcompat.Fstatat2(dirfd, pName, unix.AT_SYMLINK_NOFOLLOW)
|
st, err := syscallcompat.Fstatat2(d.dirfd, d.pName, unix.AT_SYMLINK_NOFOLLOW)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fs.ToErrno(err)
|
return fs.ToErrno(err)
|
||||||
}
|
}
|
||||||
|
@ -87,7 +87,7 @@ func (n *Node) Getattr(ctx context.Context, f fs.FileHandle, out *fuse.AttrOut)
|
||||||
|
|
||||||
// Translate ciphertext size in `out.Attr.Size` to plaintext size
|
// Translate ciphertext size in `out.Attr.Size` to plaintext size
|
||||||
cName := filepath.Base(n.Path())
|
cName := filepath.Base(n.Path())
|
||||||
n.translateSize(dirfd, cName, pName, &out.Attr)
|
n.translateSize(d.dirfd, cName, d.pName, &out.Attr)
|
||||||
|
|
||||||
if rn.args.ForceOwner != nil {
|
if rn.args.ForceOwner != nil {
|
||||||
out.Owner = *rn.args.ForceOwner
|
out.Owner = *rn.args.ForceOwner
|
||||||
|
@ -99,27 +99,26 @@ func (n *Node) Getattr(ctx context.Context, f fs.FileHandle, out *fuse.AttrOut)
|
||||||
//
|
//
|
||||||
// Symlink-safe through openBackingDir() + Readlinkat().
|
// Symlink-safe through openBackingDir() + Readlinkat().
|
||||||
func (n *Node) Readlink(ctx context.Context) (out []byte, errno syscall.Errno) {
|
func (n *Node) Readlink(ctx context.Context) (out []byte, errno syscall.Errno) {
|
||||||
dirfd, pName, errno := n.prepareAtSyscall("")
|
d, errno := n.prepareAtSyscall("")
|
||||||
if errno != 0 {
|
if errno != 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer syscall.Close(dirfd)
|
defer syscall.Close(d.dirfd)
|
||||||
|
|
||||||
cName := filepath.Base(n.Path())
|
return n.readlink(d.dirfd, d.cName, d.pName)
|
||||||
return n.readlink(dirfd, cName, pName)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open - FUSE call. Open already-existing file.
|
// Open - FUSE call. Open already-existing file.
|
||||||
//
|
//
|
||||||
// Symlink-safe through Openat().
|
// Symlink-safe through Openat().
|
||||||
func (n *Node) Open(ctx context.Context, flags uint32) (fh fs.FileHandle, fuseFlags uint32, errno syscall.Errno) {
|
func (n *Node) Open(ctx context.Context, flags uint32) (fh fs.FileHandle, fuseFlags uint32, errno syscall.Errno) {
|
||||||
dirfd, pName, errno := n.prepareAtSyscall("")
|
d, errno := n.prepareAtSyscall("")
|
||||||
if errno != 0 {
|
if errno != 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer syscall.Close(dirfd)
|
defer syscall.Close(d.dirfd)
|
||||||
|
|
||||||
fd, err := syscallcompat.Openat(dirfd, pName, syscall.O_RDONLY|syscall.O_NOFOLLOW, 0)
|
fd, err := syscallcompat.Openat(d.dirfd, d.pName, syscall.O_RDONLY|syscall.O_NOFOLLOW, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errno = fs.ToErrno(err)
|
errno = fs.ToErrno(err)
|
||||||
return
|
return
|
||||||
|
|
|
@ -23,15 +23,15 @@ import (
|
||||||
// This function is symlink-safe through use of openBackingDir() and
|
// This function is symlink-safe through use of openBackingDir() and
|
||||||
// ReadDirIVAt().
|
// ReadDirIVAt().
|
||||||
func (n *Node) Readdir(ctx context.Context) (stream fs.DirStream, errno syscall.Errno) {
|
func (n *Node) Readdir(ctx context.Context) (stream fs.DirStream, errno syscall.Errno) {
|
||||||
dirfd, cName, errno := n.prepareAtSyscall("")
|
d, errno := n.prepareAtSyscall("")
|
||||||
if errno != 0 {
|
if errno != 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer syscall.Close(dirfd)
|
defer syscall.Close(d.dirfd)
|
||||||
|
|
||||||
// Read plaintext directory
|
// Read plaintext directory
|
||||||
var entries []fuse.DirEntry
|
var entries []fuse.DirEntry
|
||||||
fd, err := syscallcompat.Openat(dirfd, cName, syscall.O_RDONLY|syscall.O_DIRECTORY|syscall.O_NOFOLLOW, 0)
|
fd, err := syscallcompat.Openat(d.dirfd, d.pName, syscall.O_RDONLY|syscall.O_DIRECTORY|syscall.O_NOFOLLOW, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fs.ToErrno(err)
|
return nil, fs.ToErrno(err)
|
||||||
}
|
}
|
||||||
|
@ -42,21 +42,20 @@ func (n *Node) Readdir(ctx context.Context) (stream fs.DirStream, errno syscall.
|
||||||
}
|
}
|
||||||
|
|
||||||
rn := n.rootNode()
|
rn := n.rootNode()
|
||||||
|
|
||||||
|
// Filter out excluded entries
|
||||||
|
entries = rn.excludeDirEntries(d, entries)
|
||||||
|
|
||||||
if rn.args.PlaintextNames {
|
if rn.args.PlaintextNames {
|
||||||
return n.readdirPlaintextnames(entries)
|
return n.readdirPlaintextnames(entries)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter out excluded entries
|
|
||||||
//TODO
|
|
||||||
//entries = rfs.excludeDirEntries(relPath, entries)
|
|
||||||
|
|
||||||
// Virtual files: at least one gocryptfs.diriv file
|
// Virtual files: at least one gocryptfs.diriv file
|
||||||
virtualFiles := []fuse.DirEntry{
|
virtualFiles := []fuse.DirEntry{
|
||||||
{Mode: virtualFileMode, Name: nametransform.DirIVFilename},
|
{Mode: virtualFileMode, Name: nametransform.DirIVFilename},
|
||||||
}
|
}
|
||||||
|
|
||||||
cipherPath := n.Path()
|
dirIV := pathiv.Derive(d.cPath, pathiv.PurposeDirIV)
|
||||||
dirIV := pathiv.Derive(cipherPath, pathiv.PurposeDirIV)
|
|
||||||
// Encrypt names
|
// Encrypt names
|
||||||
for i := range entries {
|
for i := range entries {
|
||||||
var cName string
|
var cName string
|
||||||
|
|
|
@ -47,6 +47,20 @@ func (n *Node) rootNode() *RootNode {
|
||||||
return n.Root().Operations().(*RootNode)
|
return n.Root().Operations().(*RootNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// dirfdPlus gets filled out as we gather information about a node
|
||||||
|
type dirfdPlus struct {
|
||||||
|
// fd to the directory, opened with O_DIRECTORY|O_PATH
|
||||||
|
dirfd int
|
||||||
|
// Relative plaintext path
|
||||||
|
pPath string
|
||||||
|
// Plaintext basename: filepath.Base(pPath)
|
||||||
|
pName string
|
||||||
|
// Relative ciphertext path
|
||||||
|
cPath string
|
||||||
|
// Ciphertext basename: filepath.Base(cPath)
|
||||||
|
cName string
|
||||||
|
}
|
||||||
|
|
||||||
// prepareAtSyscall returns a (dirfd, cName) pair that can be used
|
// prepareAtSyscall returns a (dirfd, cName) pair that can be used
|
||||||
// with the "___at" family of system calls (openat, fstatat, unlinkat...) to
|
// with the "___at" family of system calls (openat, fstatat, unlinkat...) to
|
||||||
// access the backing encrypted directory.
|
// access the backing encrypted directory.
|
||||||
|
@ -54,16 +68,23 @@ func (n *Node) rootNode() *RootNode {
|
||||||
// If you pass a `child` file name, the (dirfd, cName) pair will refer to
|
// If you pass a `child` file name, the (dirfd, cName) pair will refer to
|
||||||
// a child of this node.
|
// a child of this node.
|
||||||
// If `child` is empty, the (dirfd, cName) pair refers to this node itself.
|
// If `child` is empty, the (dirfd, cName) pair refers to this node itself.
|
||||||
func (n *Node) prepareAtSyscall(child string) (dirfd int, pName string, errno syscall.Errno) {
|
func (n *Node) prepareAtSyscall(child string) (d *dirfdPlus, errno syscall.Errno) {
|
||||||
p := n.Path()
|
cPath := n.Path()
|
||||||
if child != "" {
|
if child != "" {
|
||||||
p = filepath.Join(p, child)
|
cPath = filepath.Join(cPath, child)
|
||||||
}
|
}
|
||||||
rn := n.rootNode()
|
rn := n.rootNode()
|
||||||
dirfd, pName, err := rn.openBackingDir(p)
|
dirfd, pPath, err := rn.openBackingDir(cPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errno = fs.ToErrno(err)
|
errno = fs.ToErrno(err)
|
||||||
}
|
}
|
||||||
|
d = &dirfdPlus{
|
||||||
|
dirfd: dirfd,
|
||||||
|
pPath: pPath,
|
||||||
|
pName: filepath.Base(pPath),
|
||||||
|
cPath: cPath,
|
||||||
|
cName: filepath.Base(cPath),
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,28 +112,32 @@ func (n *Node) isRoot() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Node) lookupLongnameName(ctx context.Context, nameFile string, out *fuse.EntryOut) (ch *fs.Inode, errno syscall.Errno) {
|
func (n *Node) lookupLongnameName(ctx context.Context, nameFile string, out *fuse.EntryOut) (ch *fs.Inode, errno syscall.Errno) {
|
||||||
dirfd, pName1, errno := n.prepareAtSyscall("")
|
d, errno := n.prepareAtSyscall("")
|
||||||
if errno != 0 {
|
if errno != 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer syscall.Close(dirfd)
|
defer syscall.Close(d.dirfd)
|
||||||
|
|
||||||
// Find the file the gocryptfs.longname.XYZ.name file belongs to in the
|
// Find the file the gocryptfs.longname.XYZ.name file belongs to in the
|
||||||
// directory listing
|
// directory listing
|
||||||
fd, err := syscallcompat.Openat(dirfd, pName1, syscall.O_RDONLY|syscall.O_DIRECTORY|syscall.O_NOFOLLOW, 0)
|
fd, err := syscallcompat.Openat(d.dirfd, d.pName, syscall.O_RDONLY|syscall.O_DIRECTORY|syscall.O_NOFOLLOW, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errno = fs.ToErrno(err)
|
errno = fs.ToErrno(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer syscall.Close(fd)
|
defer syscall.Close(fd)
|
||||||
diriv := pathiv.Derive(n.Path(), pathiv.PurposeDirIV)
|
diriv := pathiv.Derive(d.cPath, pathiv.PurposeDirIV)
|
||||||
rn := n.rootNode()
|
rn := n.rootNode()
|
||||||
pName, cFullname, errno := rn.findLongnameParent(fd, diriv, nameFile)
|
pName, cFullname, errno := rn.findLongnameParent(fd, diriv, nameFile)
|
||||||
if errno != 0 {
|
if errno != 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if rn.isExcludedPlain(filepath.Join(d.cPath, pName)) {
|
||||||
|
errno = syscall.EPERM
|
||||||
|
return
|
||||||
|
}
|
||||||
// Get attrs from parent file
|
// Get attrs from parent file
|
||||||
st, err := syscallcompat.Fstatat2(dirfd, pName, unix.AT_SYMLINK_NOFOLLOW)
|
st, err := syscallcompat.Fstatat2(fd, pName, unix.AT_SYMLINK_NOFOLLOW)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errno = fs.ToErrno(err)
|
errno = fs.ToErrno(err)
|
||||||
return
|
return
|
||||||
|
@ -132,17 +157,17 @@ func (n *Node) lookupLongnameName(ctx context.Context, nameFile string, out *fus
|
||||||
|
|
||||||
// lookupDiriv returns a new Inode for a gocryptfs.diriv file inside `n`.
|
// lookupDiriv returns a new Inode for a gocryptfs.diriv file inside `n`.
|
||||||
func (n *Node) lookupDiriv(ctx context.Context, out *fuse.EntryOut) (ch *fs.Inode, errno syscall.Errno) {
|
func (n *Node) lookupDiriv(ctx context.Context, out *fuse.EntryOut) (ch *fs.Inode, errno syscall.Errno) {
|
||||||
dirfd, pName, errno := n.prepareAtSyscall("")
|
d, errno := n.prepareAtSyscall("")
|
||||||
if errno != 0 {
|
if errno != 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer syscall.Close(dirfd)
|
defer syscall.Close(d.dirfd)
|
||||||
st, err := syscallcompat.Fstatat2(dirfd, pName, unix.AT_SYMLINK_NOFOLLOW)
|
st, err := syscallcompat.Fstatat2(d.dirfd, d.pName, unix.AT_SYMLINK_NOFOLLOW)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errno = fs.ToErrno(err)
|
errno = fs.ToErrno(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
content := pathiv.Derive(n.Path(), pathiv.PurposeDirIV)
|
content := pathiv.Derive(d.cPath, pathiv.PurposeDirIV)
|
||||||
var vf *VirtualMemNode
|
var vf *VirtualMemNode
|
||||||
vf, errno = n.newVirtualMemNode(content, st, inoTagDirIV)
|
vf, errno = n.newVirtualMemNode(content, st, inoTagDirIV)
|
||||||
if errno != 0 {
|
if errno != 0 {
|
||||||
|
|
|
@ -2,12 +2,16 @@ package fusefrontend_reverse
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/rfjakob/gocryptfs/internal/tlog"
|
||||||
|
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
|
|
||||||
"github.com/hanwen/go-fuse/v2/fs"
|
"github.com/hanwen/go-fuse/v2/fs"
|
||||||
|
"github.com/hanwen/go-fuse/v2/fuse"
|
||||||
|
|
||||||
"github.com/rfjakob/gocryptfs/internal/contentenc"
|
"github.com/rfjakob/gocryptfs/internal/contentenc"
|
||||||
"github.com/rfjakob/gocryptfs/internal/fusefrontend"
|
"github.com/rfjakob/gocryptfs/internal/fusefrontend"
|
||||||
|
@ -28,7 +32,7 @@ type RootNode struct {
|
||||||
// Content encryption helper
|
// Content encryption helper
|
||||||
contentEnc *contentenc.ContentEnc
|
contentEnc *contentenc.ContentEnc
|
||||||
// Tests whether a path is excluded (hidden) from the user. Used by -exclude.
|
// Tests whether a path is excluded (hidden) from the user. Used by -exclude.
|
||||||
excluder *ignore.GitIgnore
|
excluder ignore.IgnoreParser
|
||||||
// inoMap translates inode numbers from different devices to unique inode
|
// inoMap translates inode numbers from different devices to unique inode
|
||||||
// numbers.
|
// numbers.
|
||||||
inoMap *inomap.InoMap
|
inoMap *inomap.InoMap
|
||||||
|
@ -38,17 +42,23 @@ type RootNode struct {
|
||||||
// In this case (reverse mode) the backing directory is plain-text and
|
// In this case (reverse mode) the backing directory is plain-text and
|
||||||
// ReverseFS provides an encrypted view.
|
// ReverseFS provides an encrypted view.
|
||||||
func NewRootNode(args fusefrontend.Args, c *contentenc.ContentEnc, n nametransform.NameTransformer) *RootNode {
|
func NewRootNode(args fusefrontend.Args, c *contentenc.ContentEnc, n nametransform.NameTransformer) *RootNode {
|
||||||
return &RootNode{
|
rn := &RootNode{
|
||||||
args: args,
|
args: args,
|
||||||
nameTransform: n,
|
nameTransform: n,
|
||||||
contentEnc: c,
|
contentEnc: c,
|
||||||
inoMap: inomap.New(),
|
inoMap: inomap.New(),
|
||||||
excluder: prepareExcluder(args),
|
|
||||||
}
|
}
|
||||||
|
if len(args.Exclude) > 0 || len(args.ExcludeWildcard) > 0 || len(args.ExcludeFrom) > 0 {
|
||||||
|
rn.excluder = prepareExcluder(args)
|
||||||
|
}
|
||||||
|
return rn
|
||||||
}
|
}
|
||||||
|
|
||||||
// You can pass either gocryptfs.longname.XYZ.name or gocryptfs.longname.XYZ.
|
// You can pass either gocryptfs.longname.XYZ.name or gocryptfs.longname.XYZ.
|
||||||
func (rn *RootNode) findLongnameParent(fd int, diriv []byte, longname string) (pName string, cFullName string, errno syscall.Errno) {
|
func (rn *RootNode) findLongnameParent(fd int, diriv []byte, longname string) (pName string, cFullName string, errno syscall.Errno) {
|
||||||
|
defer func() {
|
||||||
|
tlog.Debug.Printf("findLongnameParent: %d %x %q -> %q %q %d\n", fd, diriv, longname, pName, cFullName, errno)
|
||||||
|
}()
|
||||||
if strings.HasSuffix(longname, nametransform.LongNameSuffix) {
|
if strings.HasSuffix(longname, nametransform.LongNameSuffix) {
|
||||||
longname = nametransform.RemoveLongNameSuffix(longname)
|
longname = nametransform.RemoveLongNameSuffix(longname)
|
||||||
}
|
}
|
||||||
|
@ -84,3 +94,24 @@ func (rn *RootNode) findLongnameParent(fd int, diriv []byte, longname string) (p
|
||||||
func (rn *RootNode) isExcludedPlain(pPath string) bool {
|
func (rn *RootNode) isExcludedPlain(pPath string) bool {
|
||||||
return rn.excluder != nil && rn.excluder.MatchesPath(pPath)
|
return rn.excluder != nil && rn.excluder.MatchesPath(pPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// excludeDirEntries filters out directory entries that are "-exclude"d.
|
||||||
|
// pDir is the relative plaintext path to the directory these entries are
|
||||||
|
// from. The entries should be plaintext files.
|
||||||
|
func (rn *RootNode) excludeDirEntries(d *dirfdPlus, entries []fuse.DirEntry) (filtered []fuse.DirEntry) {
|
||||||
|
if rn.excluder == nil {
|
||||||
|
return entries
|
||||||
|
}
|
||||||
|
filtered = make([]fuse.DirEntry, 0, len(entries))
|
||||||
|
for _, entry := range entries {
|
||||||
|
// filepath.Join handles the case of pDir="" correctly:
|
||||||
|
// Join("", "foo") -> "foo". This does not: pDir + "/" + name"
|
||||||
|
p := filepath.Join(d.pPath, entry.Name)
|
||||||
|
if rn.isExcludedPlain(p) {
|
||||||
|
// Skip file
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
filtered = append(filtered, entry)
|
||||||
|
}
|
||||||
|
return filtered
|
||||||
|
}
|
||||||
|
|
|
@ -100,25 +100,24 @@ func (rn *RootNode) decryptPath(cPath string) (string, error) {
|
||||||
// and returns the fd to the directory and the decrypted name of the
|
// and returns the fd to the directory and the decrypted name of the
|
||||||
// target file. The fd/name pair is intended for use with fchownat and
|
// target file. The fd/name pair is intended for use with fchownat and
|
||||||
// friends.
|
// friends.
|
||||||
func (rn *RootNode) openBackingDir(cPath string) (dirfd int, pName string, err error) {
|
func (rn *RootNode) openBackingDir(cPath string) (dirfd int, pPath string, err error) {
|
||||||
defer func() {
|
defer func() {
|
||||||
tlog.Debug.Printf("openBackingDir %q -> %d %q %v\n", cPath, dirfd, pName, err)
|
tlog.Debug.Printf("openBackingDir %q -> %d %q %v\n", cPath, dirfd, pPath, err)
|
||||||
}()
|
}()
|
||||||
dirfd = -1
|
dirfd = -1
|
||||||
pRelPath, err := rn.decryptPath(cPath)
|
pPath, err = rn.decryptPath(cPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if rn.isExcludedPlain(pRelPath) {
|
if rn.isExcludedPlain(pPath) {
|
||||||
err = syscall.EPERM
|
err = syscall.EPERM
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Open directory, safe against symlink races
|
// Open directory, safe against symlink races
|
||||||
pDir := filepath.Dir(pRelPath)
|
pDir := filepath.Dir(pPath)
|
||||||
dirfd, err = syscallcompat.OpenDirNofollow(rn.args.Cipherdir, pDir)
|
dirfd, err = syscallcompat.OpenDirNofollow(rn.args.Cipherdir, pDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
pName = filepath.Base(pRelPath)
|
return dirfd, pPath, nil
|
||||||
return dirfd, pName, nil
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,7 +87,7 @@ func TestSymlinkDentrySize(t *testing.T) {
|
||||||
|
|
||||||
fi, err := os.Lstat(mnt + "/" + symlinkResponse.Result)
|
fi, err := os.Lstat(mnt + "/" + symlinkResponse.Result)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Lstat: %v", err)
|
t.Fatalf("Lstat: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
target, err := os.Readlink(mnt + "/" + symlinkResponse.Result)
|
target, err := os.Readlink(mnt + "/" + symlinkResponse.Result)
|
||||||
|
|
|
@ -118,6 +118,7 @@ func testExclude(t *testing.T, flag string) {
|
||||||
cExclude := encryptExcludeTestPaths(t, sock, pExclude)
|
cExclude := encryptExcludeTestPaths(t, sock, pExclude)
|
||||||
// Check that "excluded" paths are not there and "ok" paths are there
|
// Check that "excluded" paths are not there and "ok" paths are there
|
||||||
for _, v := range cExclude {
|
for _, v := range cExclude {
|
||||||
|
t.Logf("File %q should be invisible", v)
|
||||||
if test_helpers.VerifyExistence(t, mnt+"/"+v) {
|
if test_helpers.VerifyExistence(t, mnt+"/"+v) {
|
||||||
t.Errorf("File %q is visible, but should be excluded", v)
|
t.Errorf("File %q is visible, but should be excluded", v)
|
||||||
}
|
}
|
||||||
|
@ -126,6 +127,7 @@ func testExclude(t *testing.T, flag string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, v := range cOk {
|
for _, v := range cOk {
|
||||||
|
t.Logf("File %q should be visible", v)
|
||||||
if !test_helpers.VerifyExistence(t, mnt+"/"+v) {
|
if !test_helpers.VerifyExistence(t, mnt+"/"+v) {
|
||||||
t.Errorf("File %q is hidden, but should be visible", v)
|
t.Errorf("File %q is hidden, but should be visible", v)
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,7 @@ func findIno(dir string, ino uint64) string {
|
||||||
// ├── gocryptfs.longname.e31v1ax4h_F0l4jhlN8kCjaWWMq8rO9VVBZ15IYsV50 <---- child
|
// ├── gocryptfs.longname.e31v1ax4h_F0l4jhlN8kCjaWWMq8rO9VVBZ15IYsV50 <---- child
|
||||||
// └── gocryptfs.longname.e31v1ax4h_F0l4jhlN8kCjaWWMq8rO9VVBZ15IYsV50.name <---- name
|
// └── gocryptfs.longname.e31v1ax4h_F0l4jhlN8kCjaWWMq8rO9VVBZ15IYsV50.name <---- name
|
||||||
//
|
//
|
||||||
// And verifies that the inode numbers match what we expect.
|
// It verifies that the inode numbers match what we expect.
|
||||||
func TestVirtualFileIno(t *testing.T) {
|
func TestVirtualFileIno(t *testing.T) {
|
||||||
if plaintextnames {
|
if plaintextnames {
|
||||||
t.Skip("plaintextnames mode does not have virtual files")
|
t.Skip("plaintextnames mode does not have virtual files")
|
||||||
|
@ -111,7 +111,7 @@ func TestVirtualFileIno(t *testing.T) {
|
||||||
var st2 syscall.Stat_t
|
var st2 syscall.Stat_t
|
||||||
err = syscall.Lstat(encryptedParent+"/"+entry, &st2)
|
err = syscall.Lstat(encryptedParent+"/"+entry, &st2)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Logf("stat %q: %v", entry, err)
|
t.Errorf("stat %q: %v", entry, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if entry == "gocryptfs.diriv" {
|
if entry == "gocryptfs.diriv" {
|
||||||
|
|
Loading…
Reference in New Issue