syscallcompat: use O_PATH in OpenDirNofollow
This fixes the "0100 directory" problem in reverse mode, and should be slightly faster.
This commit is contained in:
parent
9ec9d0c49c
commit
930c37e03d
@ -63,9 +63,15 @@ func (rfs *ReverseFS) findLongnameParent(dir string, dirIV []byte, longname stri
|
|||||||
if hit != "" {
|
if hit != "" {
|
||||||
return hit, nil
|
return hit, nil
|
||||||
}
|
}
|
||||||
fd, err := syscallcompat.OpenDirNofollow(rfs.args.Cipherdir, dir)
|
dirfd, err := syscallcompat.OpenDirNofollow(rfs.args.Cipherdir, filepath.Dir(dir))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tlog.Warn.Printf("findLongnameParent: opendir failed: %v\n", err)
|
tlog.Warn.Printf("findLongnameParent: OpenDirNofollow failed: %v\n", err)
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
fd, err := syscallcompat.Openat(dirfd, filepath.Base(dir), syscall.O_RDONLY|syscall.O_DIRECTORY|syscall.O_NOFOLLOW, 0)
|
||||||
|
syscall.Close(dirfd)
|
||||||
|
if err != nil {
|
||||||
|
tlog.Warn.Printf("findLongnameParent: Openat failed: %v\n", err)
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
dirEntries, err := syscallcompat.Getdents(fd)
|
dirEntries, err := syscallcompat.Getdents(fd)
|
||||||
|
@ -305,7 +305,12 @@ func (rfs *ReverseFS) OpenDir(cipherPath string, context *fuse.Context) ([]fuse.
|
|||||||
return nil, fuse.ToStatus(err)
|
return nil, fuse.ToStatus(err)
|
||||||
}
|
}
|
||||||
// Read plaintext dir
|
// Read plaintext dir
|
||||||
fd, err := syscallcompat.OpenDirNofollow(rfs.args.Cipherdir, relPath)
|
dirfd, err := syscallcompat.OpenDirNofollow(rfs.args.Cipherdir, filepath.Dir(relPath))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fuse.ToStatus(err)
|
||||||
|
}
|
||||||
|
fd, err := syscallcompat.Openat(dirfd, filepath.Base(relPath), syscall.O_RDONLY|syscall.O_DIRECTORY|syscall.O_NOFOLLOW, 0)
|
||||||
|
syscall.Close(dirfd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fuse.ToStatus(err)
|
return nil, fuse.ToStatus(err)
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ func OpenDirNofollow(baseDir string, relPath string) (fd int, err error) {
|
|||||||
// Walk the directory tree
|
// Walk the directory tree
|
||||||
var dirfd2 int
|
var dirfd2 int
|
||||||
for _, name := range parts {
|
for _, name := range parts {
|
||||||
dirfd2, err = Openat(dirfd, name, syscall.O_RDONLY|syscall.O_NOFOLLOW|syscall.O_DIRECTORY, 0)
|
dirfd2, err = Openat(dirfd, name, syscall.O_RDONLY|syscall.O_NOFOLLOW|syscall.O_DIRECTORY|O_PATH, 0)
|
||||||
syscall.Close(dirfd)
|
syscall.Close(dirfd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
|
@ -9,9 +9,14 @@ import (
|
|||||||
"github.com/hanwen/go-fuse/fuse"
|
"github.com/hanwen/go-fuse/fuse"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
// O_DIRECT means oncached I/O on Linux. No direct equivalent on MacOS and defined
|
// O_DIRECT means oncached I/O on Linux. No direct equivalent on MacOS and defined
|
||||||
// to zero there.
|
// to zero there.
|
||||||
const O_DIRECT = 0
|
O_DIRECT = 0
|
||||||
|
|
||||||
|
// O_PATH is only defined on Linux
|
||||||
|
O_PATH = 0
|
||||||
|
)
|
||||||
|
|
||||||
// Sorry, fallocate is not available on OSX at all and
|
// Sorry, fallocate is not available on OSX at all and
|
||||||
// fcntl F_PREALLOCATE is not accessible from Go.
|
// fcntl F_PREALLOCATE is not accessible from Go.
|
||||||
|
@ -12,11 +12,16 @@ import (
|
|||||||
"github.com/rfjakob/gocryptfs/internal/tlog"
|
"github.com/rfjakob/gocryptfs/internal/tlog"
|
||||||
)
|
)
|
||||||
|
|
||||||
const _FALLOC_FL_KEEP_SIZE = 0x01
|
const (
|
||||||
|
_FALLOC_FL_KEEP_SIZE = 0x01
|
||||||
|
|
||||||
// O_DIRECT means oncached I/O on Linux. No direct equivalent on MacOS and defined
|
// O_DIRECT means oncached I/O on Linux. No direct equivalent on MacOS and defined
|
||||||
// to zero there.
|
// to zero there.
|
||||||
const O_DIRECT = syscall.O_DIRECT
|
O_DIRECT = syscall.O_DIRECT
|
||||||
|
|
||||||
|
// O_PATH is only defined on Linux
|
||||||
|
O_PATH = unix.O_PATH
|
||||||
|
)
|
||||||
|
|
||||||
var preallocWarn sync.Once
|
var preallocWarn sync.Once
|
||||||
|
|
||||||
|
@ -207,3 +207,33 @@ func TestTooLongSymlink(t *testing.T) {
|
|||||||
err2.Err)
|
err2.Err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test that we can traverse a directory with 0100 permissions
|
||||||
|
// (execute but no read). This used to be a problem as OpenDirNofollow opened
|
||||||
|
// all directory in the path with O_RDONLY. Now it uses O_PATH, which only needs
|
||||||
|
// the executable bit.
|
||||||
|
func Test0100Dir(t *testing.T) {
|
||||||
|
dir := dirA + "/" + t.Name()
|
||||||
|
err := os.Mkdir(dir, 0700)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
file := dir + "/hello"
|
||||||
|
err = ioutil.WriteFile(file, []byte("hello"), 0600)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
err = os.Chmod(dir, 0100)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fileReverse := dirC + "/" + t.Name() + "/hello"
|
||||||
|
fd, err := os.Open(fileReverse)
|
||||||
|
// Make sure the dir can be removed after the test is done
|
||||||
|
os.Chmod(dir, 0700)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
fd.Close()
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user