fusefrontend: Use Linkat syscall to implement Link

This commit is contained in:
Sebastian Lackner 2017-12-12 14:42:49 +01:00 committed by rfjakob
parent a24342f656
commit a85dbcab38
2 changed files with 18 additions and 16 deletions

View File

@ -540,36 +540,33 @@ func (fs *FS) Link(oldPath string, newPath string, context *fuse.Context) (code
if fs.isFiltered(newPath) { if fs.isFiltered(newPath) {
return fuse.EPERM return fuse.EPERM
} }
cOldPath, err := fs.getBackingPath(oldPath) oldDirFd, cOldName, err := fs.openBackingPath(oldPath)
if err != nil { if err != nil {
return fuse.ToStatus(err) return fuse.ToStatus(err)
} }
cNewPath, err := fs.getBackingPath(newPath) defer oldDirFd.Close()
newDirFd, cNewName, err := fs.openBackingPath(newPath)
if err != nil { if err != nil {
return fuse.ToStatus(err) return fuse.ToStatus(err)
} }
// Handle long file name defer newDirFd.Close()
cNewName := filepath.Base(cNewPath) // Handle long file name (except in PlaintextNames mode)
if !fs.args.PlaintextNames && nametransform.IsLongContent(cNewName) { if !fs.args.PlaintextNames && nametransform.IsLongContent(cNewName) {
dirfd, err := os.Open(filepath.Dir(cNewPath)) err = fs.nameTransform.WriteLongName(newDirFd, cNewName, newPath)
if err != nil { if err != nil {
return fuse.ToStatus(err) return fuse.ToStatus(err)
} }
defer dirfd.Close() // Create "gocryptfs.longfile." link
err = fs.nameTransform.WriteLongName(dirfd, cNewName, newPath) err = syscallcompat.Linkat(int(oldDirFd.Fd()), cOldName, int(newDirFd.Fd()), cNewName, 0)
if err != nil { if err != nil {
return fuse.ToStatus(err) nametransform.DeleteLongName(newDirFd, cNewName)
} }
// TODO Use syscall.Linkat once it is available in Go (it is not in Go } else {
// 1.6). // Create regular link
err = syscall.Link(cOldPath, cNewPath) err = syscallcompat.Linkat(int(oldDirFd.Fd()), cOldName, int(newDirFd.Fd()), cNewName, 0)
if err != nil {
nametransform.DeleteLongName(dirfd, cNewName)
} }
return fuse.ToStatus(err) return fuse.ToStatus(err)
} }
return fuse.ToStatus(os.Link(cOldPath, cNewPath))
}
// Access implements pathfs.Filesystem. // Access implements pathfs.Filesystem.
func (fs *FS) Access(path string, mode uint32, context *fuse.Context) (code fuse.Status) { func (fs *FS) Access(path string, mode uint32, context *fuse.Context) (code fuse.Status) {

View File

@ -38,3 +38,8 @@ func Faccessat(dirfd int, path string, mode uint32) error {
} }
return unix.Faccessat(dirfd, path, mode, 0) return unix.Faccessat(dirfd, path, mode, 0)
} }
// Linkat exists both in Linux and in MacOS 10.10+.
func Linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) {
return unix.Linkat(olddirfd, oldpath, newdirfd, newpath, flags)
}