diff options
Diffstat (limited to 'internal')
| -rw-r--r-- | internal/fusefrontend/fs_dir.go | 44 | ||||
| -rw-r--r-- | internal/nametransform/diriv.go | 7 | ||||
| -rw-r--r-- | internal/syscallcompat/sys_darwin.go | 17 | ||||
| -rw-r--r-- | internal/syscallcompat/sys_linux.go | 5 | 
4 files changed, 46 insertions, 27 deletions
| diff --git a/internal/fusefrontend/fs_dir.go b/internal/fusefrontend/fs_dir.go index ae150b5..4ffaaff 100644 --- a/internal/fusefrontend/fs_dir.go +++ b/internal/fusefrontend/fs_dir.go @@ -24,7 +24,7 @@ import (  const dsStoreName = ".DS_Store" -func (fs *FS) mkdirWithIv(cPath string, mode uint32) error { +func (fs *FS) mkdirWithIv(dirfd *os.File, cName string, mode uint32) error {  	// Between the creation of the directory and the creation of gocryptfs.diriv  	// the directory is inconsistent. Take the lock to prevent other readers  	// from seeing it. @@ -32,14 +32,14 @@ func (fs *FS) mkdirWithIv(cPath string, mode uint32) error {  	// The new directory may take the place of an older one that is still in the cache  	fs.nameTransform.DirIVCache.Clear()  	defer fs.dirIVLock.Unlock() -	err := os.Mkdir(cPath, os.FileMode(mode)) +	err := syscallcompat.Mkdirat(int(dirfd.Fd()), cName, mode)  	if err != nil {  		return err  	}  	// Create gocryptfs.diriv -	err = nametransform.WriteDirIV(cPath) +	err = nametransform.WriteDirIV(dirfd, cName)  	if err != nil { -		err2 := syscall.Rmdir(cPath) +		err2 := syscallcompat.Unlinkat(int(dirfd.Fd()), cName, unix.AT_REMOVEDIR)  		if err2 != nil {  			tlog.Warn.Printf("mkdirWithIv: rollback failed: %v", err2)  		} @@ -52,17 +52,19 @@ func (fs *FS) Mkdir(newPath string, mode uint32, context *fuse.Context) (code fu  	if fs.isFiltered(newPath) {  		return fuse.EPERM  	} -	cPath, err := fs.getBackingPath(newPath) +	dirfd, cName, err := fs.openBackingPath(newPath)  	if err != nil {  		return fuse.ToStatus(err)  	} +	defer dirfd.Close()  	if fs.args.PlaintextNames { -		err = os.Mkdir(cPath, os.FileMode(mode)) +		err = syscallcompat.Mkdirat(int(dirfd.Fd()), cName, mode)  		// Set owner  		if fs.args.PreserveOwner { -			err = os.Lchown(cPath, int(context.Owner.Uid), int(context.Owner.Gid)) +			err = syscallcompat.Fchownat(int(dirfd.Fd()), cName, int(context.Owner.Uid), +				int(context.Owner.Gid), unix.AT_SYMLINK_NOFOLLOW)  			if err != nil { -				tlog.Warn.Printf("Mkdir: Lchown failed: %v", err) +				tlog.Warn.Printf("Mkdir: Fchownat failed: %v", err)  			}  		}  		return fuse.ToStatus(err) @@ -73,15 +75,7 @@ func (fs *FS) Mkdir(newPath string, mode uint32, context *fuse.Context) (code fu  	mode = mode | 0300  	// Handle long file name -	cName := filepath.Base(cPath)  	if nametransform.IsLongContent(cName) { -		var dirfd *os.File -		dirfd, err = os.Open(filepath.Dir(cPath)) -		if err != nil { -			return fuse.ToStatus(err) -		} -		defer dirfd.Close() -  		// Create ".name"  		err = fs.nameTransform.WriteLongName(dirfd, cName, newPath)  		if err != nil { @@ -89,33 +83,35 @@ func (fs *FS) Mkdir(newPath string, mode uint32, context *fuse.Context) (code fu  		}  		// Create directory -		err = fs.mkdirWithIv(cPath, mode) +		err = fs.mkdirWithIv(dirfd, cName, mode)  		if err != nil {  			nametransform.DeleteLongName(dirfd, cName)  			return fuse.ToStatus(err)  		}  	} else { -		err = fs.mkdirWithIv(cPath, mode) +		err = fs.mkdirWithIv(dirfd, cName, mode)  		if err != nil {  			return fuse.ToStatus(err)  		}  	}  	// Set permissions back to what the user wanted  	if origMode != mode { -		err = os.Chmod(cPath, os.FileMode(origMode)) +		err = syscallcompat.Fchmodat(int(dirfd.Fd()), cName, origMode, unix.AT_SYMLINK_NOFOLLOW)  		if err != nil { -			tlog.Warn.Printf("Mkdir: Chmod failed: %v", err) +			tlog.Warn.Printf("Mkdir: Fchmodat failed: %v", err)  		}  	}  	// Set owner  	if fs.args.PreserveOwner { -		err = os.Lchown(cPath, int(context.Owner.Uid), int(context.Owner.Gid)) +		err = syscallcompat.Fchownat(int(dirfd.Fd()), cName, int(context.Owner.Uid), +			int(context.Owner.Gid), unix.AT_SYMLINK_NOFOLLOW)  		if err != nil { -			tlog.Warn.Printf("Mkdir: Lchown 1 failed: %v", err) +			tlog.Warn.Printf("Mkdir: Fchownat 1 failed: %v", err)  		} -		err = os.Lchown(filepath.Join(cPath, nametransform.DirIVFilename), int(context.Owner.Uid), int(context.Owner.Gid)) +		err = syscallcompat.Fchownat(int(dirfd.Fd()), filepath.Join(cName, nametransform.DirIVFilename), +			int(context.Owner.Uid), int(context.Owner.Gid), unix.AT_SYMLINK_NOFOLLOW)  		if err != nil { -			tlog.Warn.Printf("Mkdir: Lchown 2 failed: %v", err) +			tlog.Warn.Printf("Mkdir: Fchownat 2 failed: %v", err)  		}  	}  	return fuse.OK diff --git a/internal/nametransform/diriv.go b/internal/nametransform/diriv.go index ffaf785..fe289c6 100644 --- a/internal/nametransform/diriv.go +++ b/internal/nametransform/diriv.go @@ -75,16 +75,17 @@ func fdReadDirIV(fd *os.File) (iv []byte, err error) {  // WriteDirIV - create diriv file inside "dir" (absolute ciphertext path)  // This function is exported because it is used from pathfs_frontend, main,  // and also the automated tests. -func WriteDirIV(dir string) error { +func WriteDirIV(dirfd *os.File, dir string) error {  	iv := cryptocore.RandBytes(DirIVLen)  	file := filepath.Join(dir, DirIVFilename)  	// 0400 permissions: gocryptfs.diriv should never be modified after creation.  	// Don't use "ioutil.WriteFile", it causes trouble on NFS: https://github.com/rfjakob/gocryptfs/issues/105 -	fd, err := os.OpenFile(file, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0400) +	fdRaw, err := syscallcompat.Openat(int(dirfd.Fd()), file, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0400)  	if err != nil { -		tlog.Warn.Printf("WriteDirIV: OpenFile: %v", err) +		tlog.Warn.Printf("WriteDirIV: Openat: %v", err)  		return err  	} +	fd := os.NewFile(uintptr(fdRaw), file)  	_, err = fd.Write(iv)  	if err != nil {  		tlog.Warn.Printf("WriteDirIV: Write: %v", err) diff --git a/internal/syscallcompat/sys_darwin.go b/internal/syscallcompat/sys_darwin.go index 367f67d..39a225f 100644 --- a/internal/syscallcompat/sys_darwin.go +++ b/internal/syscallcompat/sys_darwin.go @@ -187,3 +187,20 @@ func Symlinkat(oldpath string, newdirfd int, newpath string) (err error) {  	defer syscall.Fchdir(cwd)  	return syscall.Symlink(oldpath, newpath)  } + +// Poor man's Mkdirat. +func Mkdirat(dirfd int, path string, mode uint32) (err error) { +	chdirMutex.Lock() +	defer chdirMutex.Unlock() +	cwd, err := syscall.Open(".", syscall.O_RDONLY, 0) +	if err != nil { +		return err +	} +	defer syscall.Close(cwd) +	err = syscall.Fchdir(dirfd) +	if err != nil { +		return err +	} +	defer syscall.Fchdir(cwd) +	return syscall.Mkdir(path, mode) +} diff --git a/internal/syscallcompat/sys_linux.go b/internal/syscallcompat/sys_linux.go index 4fe44fd..1ea56b5 100644 --- a/internal/syscallcompat/sys_linux.go +++ b/internal/syscallcompat/sys_linux.go @@ -109,3 +109,8 @@ func Symlinkat(oldpath string, newdirfd int, newpath string) (err error) {  	}  	return  } + +// Mkdirat syscall. +func Mkdirat(dirfd int, path string, mode uint32) (err error) { +	return syscall.Mkdirat(dirfd, path, mode) +} | 
