fusefrontend: make OpenDir() symlink-safe
Interestingly, little or no performance impact: $ ./benchmark.bash Testing gocryptfs at /tmp/benchmark.bash.39W: gocryptfs v1.6-42-g30c2349-dirty; go-fuse v20170619-66-g6df8ddc; 2018-11-04 go1.11 Downloading linux-3.0.tar.gz /tmp/linux-3.0.tar.gz 100%[=========================================================================>] 92.20M 2.93MB/s in 31s 2018-11-04 21:44:44 URL:https://cdn.kernel.org/pub/linux/kernel/v3.0/linux-3.0.tar.gz [96675825/96675825] -> "/tmp/linux-3.0.tar.gz" [1] WRITE: 262144000 bytes (262 MB, 250 MiB) copied, 1.1808 s, 222 MB/s READ: 262144000 bytes (262 MB, 250 MiB) copied, 0.866438 s, 303 MB/s UNTAR: 24.745 MD5: 12.050 LS: 3.525 RM: 9.544 Note: kernel has been updated: $ uname -a Linux brikett 4.18.16-200.fc28.x86_64 #1 SMP Sat Oct 20 23:53:47 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
This commit is contained in:
parent
de3a2c1895
commit
21f1f858b9
@ -260,18 +260,21 @@ retry:
|
|||||||
return fuse.OK
|
return fuse.OK
|
||||||
}
|
}
|
||||||
|
|
||||||
// OpenDir implements pathfs.FileSystem
|
// OpenDir - FUSE call
|
||||||
|
//
|
||||||
|
// This function is symlink-safe through use of openBackingDir() and
|
||||||
|
// ReadDirIVAt().
|
||||||
func (fs *FS) OpenDir(dirName string, context *fuse.Context) ([]fuse.DirEntry, fuse.Status) {
|
func (fs *FS) OpenDir(dirName string, context *fuse.Context) ([]fuse.DirEntry, fuse.Status) {
|
||||||
tlog.Debug.Printf("OpenDir(%s)", dirName)
|
tlog.Debug.Printf("OpenDir(%s)", dirName)
|
||||||
cDirName, err := fs.encryptPath(dirName)
|
parentDirFd, cDirName, err := fs.openBackingDir(dirName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fuse.ToStatus(err)
|
return nil, fuse.ToStatus(err)
|
||||||
}
|
}
|
||||||
|
defer syscall.Close(parentDirFd)
|
||||||
// Read ciphertext directory
|
// Read ciphertext directory
|
||||||
cDirAbsPath := filepath.Join(fs.args.Cipherdir, cDirName)
|
|
||||||
var cipherEntries []fuse.DirEntry
|
var cipherEntries []fuse.DirEntry
|
||||||
var status fuse.Status
|
var status fuse.Status
|
||||||
fd, err := syscall.Open(cDirAbsPath, syscall.O_RDONLY|syscall.O_NOFOLLOW, 0)
|
fd, err := syscallcompat.Openat(parentDirFd, cDirName, syscall.O_RDONLY|syscall.O_NOFOLLOW, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fuse.ToStatus(err)
|
return nil, fuse.ToStatus(err)
|
||||||
}
|
}
|
||||||
@ -283,23 +286,16 @@ func (fs *FS) OpenDir(dirName string, context *fuse.Context) ([]fuse.DirEntry, f
|
|||||||
// Get DirIV (stays nil if PlaintextNames is used)
|
// Get DirIV (stays nil if PlaintextNames is used)
|
||||||
var cachedIV []byte
|
var cachedIV []byte
|
||||||
if !fs.args.PlaintextNames {
|
if !fs.args.PlaintextNames {
|
||||||
cachedIV, _ = fs.nameTransform.DirIVCache.Lookup(dirName)
|
// Read the DirIV from disk
|
||||||
if cachedIV == nil {
|
cachedIV, err = nametransform.ReadDirIVAt(fd)
|
||||||
// Read the DirIV from disk and store it in the cache
|
if err != nil {
|
||||||
fs.dirIVLock.RLock()
|
// The directory itself does not exist
|
||||||
cachedIV, err = nametransform.ReadDirIV(cDirAbsPath)
|
if err == syscall.ENOENT {
|
||||||
if err != nil {
|
return nil, fuse.ENOENT
|
||||||
fs.dirIVLock.RUnlock()
|
|
||||||
// The directory itself does not exist
|
|
||||||
if err == syscall.ENOENT {
|
|
||||||
return nil, fuse.ENOENT
|
|
||||||
}
|
|
||||||
// Any other problem warrants an error message
|
|
||||||
tlog.Warn.Printf("OpenDir %q: could not read gocryptfs.diriv: %v", cDirName, err)
|
|
||||||
return nil, fuse.EIO
|
|
||||||
}
|
}
|
||||||
fs.nameTransform.DirIVCache.Store(dirName, cachedIV, cDirName)
|
// Any other problem warrants an error message
|
||||||
fs.dirIVLock.RUnlock()
|
tlog.Warn.Printf("OpenDir %q: could not read gocryptfs.diriv: %v", cDirName, err)
|
||||||
|
return nil, fuse.EIO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Decrypted directory entries
|
// Decrypted directory entries
|
||||||
|
@ -29,6 +29,9 @@ const (
|
|||||||
// This function is exported because it allows for an efficient readdir implementation.
|
// This function is exported because it allows for an efficient readdir implementation.
|
||||||
// If the directory itself cannot be opened, a syscall error will be returned.
|
// If the directory itself cannot be opened, a syscall error will be returned.
|
||||||
// Otherwise, a fmt.Errorf() error value is returned with the details.
|
// Otherwise, a fmt.Errorf() error value is returned with the details.
|
||||||
|
//
|
||||||
|
// TODO: this function is not symlink-safe and should be deleted once the only
|
||||||
|
// remaining user, EncryptPathDirIV(), is gone.
|
||||||
func ReadDirIV(dir string) (iv []byte, err error) {
|
func ReadDirIV(dir string) (iv []byte, err error) {
|
||||||
fd, err := os.Open(filepath.Join(dir, DirIVFilename))
|
fd, err := os.Open(filepath.Join(dir, DirIVFilename))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Loading…
Reference in New Issue
Block a user