aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakob Unterwurzacher2016-07-03 20:05:32 +0200
committerJakob Unterwurzacher2016-07-03 20:05:32 +0200
commit79851bf6cc391f1150be387631159d553d5426f3 (patch)
tree560f3228054ad8a5a37500de5aa21832c021a03e
parent9b725c15cf50cfb85ec6ec88c47843092775dedc (diff)
syscallcompat: OSX: add Renamat wrapper
Adds a poor man's renameat implementation for OSX.
-rw-r--r--internal/fusefrontend/fs.go9
-rw-r--r--internal/fusefrontend/fs_dir.go5
-rw-r--r--internal/syscallcompat/sys_darwin.go91
-rw-r--r--internal/syscallcompat/sys_linux.go8
4 files changed, 83 insertions, 30 deletions
diff --git a/internal/fusefrontend/fs.go b/internal/fusefrontend/fs.go
index 58881d1..cd9eec1 100644
--- a/internal/fusefrontend/fs.go
+++ b/internal/fusefrontend/fs.go
@@ -4,6 +4,7 @@ package fusefrontend
import (
"encoding/base64"
+ "fmt"
"os"
"path/filepath"
"sync"
@@ -17,6 +18,7 @@ import (
"github.com/rfjakob/gocryptfs/internal/contentenc"
"github.com/rfjakob/gocryptfs/internal/cryptocore"
"github.com/rfjakob/gocryptfs/internal/nametransform"
+ "github.com/rfjakob/gocryptfs/internal/syscallcompat"
"github.com/rfjakob/gocryptfs/internal/tlog"
)
@@ -385,6 +387,7 @@ func (fs *FS) Rename(oldPath string, newPath string, context *fuse.Context) (cod
}
defer oldDirFd.Close()
finalOldDirFd = int(oldDirFd.Fd())
+ // Use relative path
finalOldPath = cOldName
}
// Handle long destination file name
@@ -399,6 +402,7 @@ func (fs *FS) Rename(oldPath string, newPath string, context *fuse.Context) (cod
}
defer newDirFd.Close()
finalNewDirFd = int(newDirFd.Fd())
+ // Use relative path
finalNewPath = cNewName
// Create destination .name file
err = fs.nameTransform.WriteLongName(newDirFd, cNewName, newPath)
@@ -407,7 +411,8 @@ func (fs *FS) Rename(oldPath string, newPath string, context *fuse.Context) (cod
}
}
// Actual rename
- err = syscall.Renameat(finalOldDirFd, finalOldPath, finalNewDirFd, finalNewPath)
+ fmt.Printf("Renameat oldfd=%d oldpath=%s newfd=%d newpath=%s\n", finalOldDirFd, finalOldPath, finalNewDirFd, finalNewPath)
+ err = syscallcompat.Renameat(finalOldDirFd, finalOldPath, finalNewDirFd, finalNewPath)
if err == syscall.ENOTEMPTY || err == syscall.EEXIST {
// If an empty directory is overwritten we will always get an error as
// the "empty" directory will still contain gocryptfs.diriv.
@@ -416,7 +421,7 @@ func (fs *FS) Rename(oldPath string, newPath string, context *fuse.Context) (cod
// again.
tlog.Debug.Printf("Rename: Handling ENOTEMPTY")
if fs.Rmdir(newPath, context) == fuse.OK {
- err = syscall.Renameat(finalOldDirFd, finalOldPath, finalNewDirFd, finalNewPath)
+ err = syscallcompat.Renameat(finalOldDirFd, finalOldPath, finalNewDirFd, finalNewPath)
}
}
if err != nil {
diff --git a/internal/fusefrontend/fs_dir.go b/internal/fusefrontend/fs_dir.go
index 4657b95..699ec7b 100644
--- a/internal/fusefrontend/fs_dir.go
+++ b/internal/fusefrontend/fs_dir.go
@@ -14,6 +14,7 @@ import (
"github.com/rfjakob/gocryptfs/internal/configfile"
"github.com/rfjakob/gocryptfs/internal/cryptocore"
"github.com/rfjakob/gocryptfs/internal/nametransform"
+ "github.com/rfjakob/gocryptfs/internal/syscallcompat"
"github.com/rfjakob/gocryptfs/internal/tlog"
)
@@ -168,7 +169,7 @@ func (fs *FS) Rmdir(path string, context *fuse.Context) (code fuse.Status) {
// Protect against concurrent readers.
fs.dirIVLock.Lock()
defer fs.dirIVLock.Unlock()
- err = syscall.Renameat(int(dirfd.Fd()), nametransform.DirIVFilename,
+ err = syscallcompat.Renameat(int(dirfd.Fd()), nametransform.DirIVFilename,
int(parentDirFd.Fd()), tmpName)
if err != nil {
tlog.Warn.Printf("Rmdir: Renaming %s to %s failed: %v",
@@ -182,7 +183,7 @@ func (fs *FS) Rmdir(path string, context *fuse.Context) (code fuse.Status) {
if err != nil {
// This can happen if another file in the directory was created in the
// meantime, undo the rename
- err2 := syscall.Renameat(int(parentDirFd.Fd()), tmpName,
+ err2 := syscallcompat.Renameat(int(parentDirFd.Fd()), tmpName,
int(dirfd.Fd()), nametransform.DirIVFilename)
if err != nil {
tlog.Warn.Printf("Rmdir: Rename rollback failed: %v", err2)
diff --git a/internal/syscallcompat/sys_darwin.go b/internal/syscallcompat/sys_darwin.go
index 81e1b15..7d39484 100644
--- a/internal/syscallcompat/sys_darwin.go
+++ b/internal/syscallcompat/sys_darwin.go
@@ -2,44 +2,87 @@ package syscallcompat
import (
"os"
+ "path/filepath"
"sync"
"syscall"
)
-// prealloc - preallocate space without changing the file size. This prevents
-// us from running out of space in the middle of an operation.
-func Prealloc(fd int, off int64, len int64) (err error) {
- //
- // Sorry, fallocate is not available on OSX at all and
- // fcntl F_PREALLOCATE is not accessible from Go.
- //
- // See https://github.com/rfjakob/gocryptfs/issues/18 if you want to help.
+// Sorry, fallocate is not available on OSX at all and
+// fcntl F_PREALLOCATE is not accessible from Go.
+// See https://github.com/rfjakob/gocryptfs/issues/18 if you want to help.
+func EnospcPrealloc(fd int, off int64, len int64) (err error) {
return nil
}
-var openatLock sync.Mutex
+// See above.
+func Fallocate(fd int, mode uint32, off int64, len int64) (err error) {
+ return syscall.EOPNOTSUPP
+}
-// Poor man's Openat:
-// 1) fchdir to the dirfd
-// 2) open the file
-// 3) chdir back.
+var chdirMutex sync.Mutex
+
+// Poor man's Openat
func Openat(dirfd int, path string, flags int, mode uint32) (fd int, err error) {
- openatLock.Lock()
- defer openatLock.Unlock()
+ chdirMutex.Lock()
+ defer chdirMutex.Unlock()
+ if !filepath.IsAbs(path) {
+ // Save the old working directory
+ oldWd, err := os.Getwd()
+ if err != nil {
+ return -1, err
+ }
+ // Chdir to target directory
+ err = syscall.Fchdir(dirfd)
+ if err != nil {
+ return -1, err
+ }
+ // Chdir back at the end
+ defer os.Chdir(oldWd)
+ }
+ return syscall.Open(path, flags, mode)
+}
- oldWd, err := os.Getwd()
+// Poor man's Renameat
+func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) {
+ chdirMutex.Lock()
+ defer chdirMutex.Unlock()
+ // Unless both paths are absolute we have to save the old working dir and
+ // Chdir(oldWd) back to it in the end. If we error out before the first
+ // chdir, Chdir(oldWd) is unneccassary but does no harm.
+ if !filepath.IsAbs(oldpath) || !filepath.IsAbs(newpath) {
+ oldWd, err := os.Getwd()
+ if err != nil {
+ return err
+ }
+ defer os.Chdir(oldWd)
+ }
+ // Make oldpath absolute
+ oldpath, err = dirfdAbs(olddirfd, oldpath)
if err != nil {
- return -1, err
+ return err
}
- err = syscall.Fchdir(dirfd)
+ // Make newpath absolute
+ newpath, err = dirfdAbs(newdirfd, newpath)
if err != nil {
- return -1, err
+ return err
}
- defer os.Chdir(oldWd)
-
- return syscall.Open(path, flags, mode)
+ return syscall.Rename(oldpath, newpath)
}
-func Fallocate(fd int, mode uint32, off int64, len int64) (err error) {
- return syscall.EOPNOTSUPP
+// dirfdAbs transforms the dirfd-relative "path" to an absolute one. If the
+// path is not already absolute, this function will change the working
+// directory. The caller has to chdir back.
+func dirfdAbs(dirfd int, path string) (absPath string, err error) {
+ if filepath.IsAbs(path) {
+ return path, nil
+ }
+ err = syscall.Fchdir(dirfd)
+ if err != nil {
+ return "", err
+ }
+ wd, err := os.Getwd()
+ if err != nil {
+ return "", err
+ }
+ return filepath.Join(wd, path), nil
}
diff --git a/internal/syscallcompat/sys_linux.go b/internal/syscallcompat/sys_linux.go
index ca6df95..e12d100 100644
--- a/internal/syscallcompat/sys_linux.go
+++ b/internal/syscallcompat/sys_linux.go
@@ -37,10 +37,14 @@ func EnospcPrealloc(fd int, off int64, len int64) (err error) {
}
}
+func Fallocate(fd int, mode uint32, off int64, len int64) (err error) {
+ return syscall.Fallocate(fd, mode, off, len)
+}
+
func Openat(dirfd int, path string, flags int, mode uint32) (fd int, err error) {
return syscall.Openat(dirfd, path, flags, mode)
}
-func Fallocate(fd int, mode uint32, off int64, len int64) (err error) {
- return syscall.Fallocate(fd, mode, off, len)
+func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) {
+ return syscall.Renameat(olddirfd, oldpath, newdirfd, newpath)
}