syscallcompat: Introduce unlinkat syscall with flags argument

This commit is contained in:
Sebastian Lackner 2017-11-29 12:23:40 +01:00
parent 5d44a31b41
commit 0f44c617d0
5 changed files with 34 additions and 19 deletions

View File

@ -388,7 +388,7 @@ func (fs *FS) Unlink(path string, context *fuse.Context) (code fuse.Status) {
} }
defer dirfd.Close() defer dirfd.Close()
// Delete content // Delete content
err = syscallcompat.Unlinkat(int(dirfd.Fd()), cName) err = syscallcompat.Unlinkat(int(dirfd.Fd()), cName, 0)
if err != nil { if err != nil {
return fuse.ToStatus(err) return fuse.ToStatus(err)
} }

View File

@ -11,6 +11,8 @@ import (
"sync" "sync"
"syscall" "syscall"
"golang.org/x/sys/unix"
"github.com/hanwen/go-fuse/fuse" "github.com/hanwen/go-fuse/fuse"
"github.com/rfjakob/gocryptfs/internal/configfile" "github.com/rfjakob/gocryptfs/internal/configfile"
@ -231,9 +233,7 @@ retry:
return fuse.ToStatus(err) return fuse.ToStatus(err)
} }
// Actual Rmdir // Actual Rmdir
// TODO Use syscall.Unlinkat with the AT_REMOVEDIR flag once it is available err = syscallcompat.Unlinkat(int(parentDirFd.Fd()), cName, unix.AT_REMOVEDIR)
// in Go
err = syscall.Rmdir(cPath)
if err != nil { if err != nil {
// This can happen if another file in the directory was created in the // This can happen if another file in the directory was created in the
// meantime, undo the rename // meantime, undo the rename
@ -245,7 +245,7 @@ retry:
return fuse.ToStatus(err) return fuse.ToStatus(err)
} }
// Delete "gocryptfs.diriv.rmdir.XYZ" // Delete "gocryptfs.diriv.rmdir.XYZ"
err = syscallcompat.Unlinkat(int(parentDirFd.Fd()), tmpName) err = syscallcompat.Unlinkat(int(parentDirFd.Fd()), tmpName, 0)
if err != nil { if err != nil {
tlog.Warn.Printf("Rmdir: Could not clean up %s: %v", tmpName, err) tlog.Warn.Printf("Rmdir: Could not clean up %s: %v", tmpName, err)
} }

View File

@ -90,7 +90,7 @@ func ReadLongName(path string) (string, error) {
// DeleteLongName deletes "hashName.name". // DeleteLongName deletes "hashName.name".
func DeleteLongName(dirfd *os.File, hashName string) error { func DeleteLongName(dirfd *os.File, hashName string) error {
err := syscallcompat.Unlinkat(int(dirfd.Fd()), hashName+LongNameSuffix) err := syscallcompat.Unlinkat(int(dirfd.Fd()), hashName+LongNameSuffix, 0)
if err != nil { if err != nil {
tlog.Warn.Printf("DeleteLongName: %v", err) tlog.Warn.Printf("DeleteLongName: %v", err)
} }

View File

@ -6,6 +6,8 @@ import (
"path/filepath" "path/filepath"
"sync" "sync"
"syscall" "syscall"
"golang.org/x/sys/unix"
) )
// Sorry, fallocate is not available on OSX at all and // Sorry, fallocate is not available on OSX at all and
@ -71,21 +73,24 @@ func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) error
} }
// Poor man's Unlinkat // Poor man's Unlinkat
func Unlinkat(dirfd int, path string) error { func Unlinkat(dirfd int, path string, flags int) (err error) {
chdirMutex.Lock() chdirMutex.Lock()
defer chdirMutex.Unlock() defer chdirMutex.Unlock()
if !filepath.IsAbs(path) { cwd, err := syscall.Open(".", syscall.O_RDONLY, 0)
oldWd, err := os.Getwd()
if err != nil {
return err
}
defer os.Chdir(oldWd)
}
path, err := dirfdAbs(dirfd, path)
if err != nil { if err != nil {
return err return err
} }
return syscall.Unlink(path) defer syscall.Close(cwd)
err = syscall.Fchdir(dirfd)
if err != nil {
return err
}
defer syscall.Fchdir(cwd)
if (flags & unix.AT_REMOVEDIR) != 0 {
return syscall.Rmdir(path)
} else {
return syscall.Unlink(path)
}
} }
// Poor man's Mknodat // Poor man's Mknodat

View File

@ -54,9 +54,19 @@ func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err e
return syscall.Renameat(olddirfd, oldpath, newdirfd, newpath) return syscall.Renameat(olddirfd, oldpath, newdirfd, newpath)
} }
// Unlinkat wraps the Unlinkat syscall. // Unlinkat syscall. In old versions the 'flags' argument was missing, so
func Unlinkat(dirfd int, path string) error { // manually call it by using the corresponding syscall number.
return syscall.Unlinkat(dirfd, path) func Unlinkat(dirfd int, path string, flags int) (err error) {
var _p0 *byte
_p0, err = syscall.BytePtrFromString(path)
if err != nil {
return
}
_, _, e1 := syscall.Syscall(syscall.SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags))
if e1 != 0 {
err = e1
}
return
} }
// Mknodat wraps the Mknodat syscall. // Mknodat wraps the Mknodat syscall.