fusefrontend: get rid of os.File* wrapping
Directly use int file descriptors for the dirfd and get rid of one level of indirection.
This commit is contained in:
parent
22fba4ac3e
commit
c270b21efc
@ -96,7 +96,7 @@ func initDir(args *argContainer) {
|
|||||||
// Forward mode with filename encryption enabled needs a gocryptfs.diriv file
|
// Forward mode with filename encryption enabled needs a gocryptfs.diriv file
|
||||||
// in the root dir
|
// in the root dir
|
||||||
if !args.plaintextnames && !args.reverse {
|
if !args.plaintextnames && !args.reverse {
|
||||||
err = nametransform.WriteDirIV(nil, args.cipherdir)
|
err = nametransform.WriteDirIV(-1, args.cipherdir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tlog.Fatal.Println(err)
|
tlog.Fatal.Println(err)
|
||||||
os.Exit(exitcodes.Init)
|
os.Exit(exitcodes.Init)
|
||||||
|
@ -129,7 +129,7 @@ func (fs *FS) Open(path string, flags uint32, context *fuse.Context) (fuseFile n
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fuse.ToStatus(err)
|
return nil, fuse.ToStatus(err)
|
||||||
}
|
}
|
||||||
fd, err := syscallcompat.Openat(int(dirfd.Fd()), cName, newFlags, 0)
|
fd, err := syscallcompat.Openat(dirfd, cName, newFlags, 0)
|
||||||
// Handle a few specific errors
|
// Handle a few specific errors
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == syscall.EMFILE {
|
if err == syscall.EMFILE {
|
||||||
@ -150,8 +150,8 @@ func (fs *FS) Open(path string, flags uint32, context *fuse.Context) (fuseFile n
|
|||||||
// problem if the file permissions do not allow reading (i.e. 0200 permissions).
|
// problem if the file permissions do not allow reading (i.e. 0200 permissions).
|
||||||
// This function works around that problem by chmod'ing the file, obtaining a fd,
|
// This function works around that problem by chmod'ing the file, obtaining a fd,
|
||||||
// and chmod'ing it back.
|
// and chmod'ing it back.
|
||||||
func (fs *FS) openWriteOnlyFile(dirfd *os.File, cName string, newFlags int) (fuseFile nodefs.File, status fuse.Status) {
|
func (fs *FS) openWriteOnlyFile(dirfd int, cName string, newFlags int) (fuseFile nodefs.File, status fuse.Status) {
|
||||||
woFd, err := syscallcompat.Openat(int(dirfd.Fd()), cName, syscall.O_WRONLY|syscall.O_NOFOLLOW, 0)
|
woFd, err := syscallcompat.Openat(dirfd, cName, syscall.O_WRONLY|syscall.O_NOFOLLOW, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fuse.ToStatus(err)
|
return nil, fuse.ToStatus(err)
|
||||||
}
|
}
|
||||||
@ -186,7 +186,7 @@ func (fs *FS) openWriteOnlyFile(dirfd *os.File, cName string, newFlags int) (fus
|
|||||||
tlog.Warn.Printf("openWriteOnlyFile: reverting permissions failed: %v", err2)
|
tlog.Warn.Printf("openWriteOnlyFile: reverting permissions failed: %v", err2)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
rwFd, err := syscallcompat.Openat(int(dirfd.Fd()), cName, newFlags, 0)
|
rwFd, err := syscallcompat.Openat(dirfd, cName, newFlags, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fuse.ToStatus(err)
|
return nil, fuse.ToStatus(err)
|
||||||
}
|
}
|
||||||
@ -210,12 +210,12 @@ func (fs *FS) Create(path string, flags uint32, mode uint32, context *fuse.Conte
|
|||||||
|
|
||||||
// Handle long file name
|
// Handle long file name
|
||||||
if !fs.args.PlaintextNames && nametransform.IsLongContent(cName) {
|
if !fs.args.PlaintextNames && nametransform.IsLongContent(cName) {
|
||||||
var dirfd *os.File
|
var dirfd int
|
||||||
dirfd, err = os.Open(filepath.Dir(cPath))
|
dirfd, err = syscall.Open(filepath.Dir(cPath), syscall.O_RDONLY|syscall.O_DIRECTORY, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fuse.ToStatus(err)
|
return nil, fuse.ToStatus(err)
|
||||||
}
|
}
|
||||||
defer dirfd.Close()
|
defer syscall.Close(dirfd)
|
||||||
|
|
||||||
// Create ".name"
|
// Create ".name"
|
||||||
err = fs.nameTransform.WriteLongName(dirfd, cName, path)
|
err = fs.nameTransform.WriteLongName(dirfd, cName, path)
|
||||||
@ -225,7 +225,7 @@ func (fs *FS) Create(path string, flags uint32, mode uint32, context *fuse.Conte
|
|||||||
|
|
||||||
// Create content
|
// Create content
|
||||||
var fdRaw int
|
var fdRaw int
|
||||||
fdRaw, err = syscallcompat.Openat(int(dirfd.Fd()), cName, newFlags|os.O_CREATE|os.O_EXCL, mode)
|
fdRaw, err = syscallcompat.Openat(dirfd, cName, newFlags|os.O_CREATE|os.O_EXCL, mode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
nametransform.DeleteLongName(dirfd, cName)
|
nametransform.DeleteLongName(dirfd, cName)
|
||||||
return nil, fuse.ToStatus(err)
|
return nil, fuse.ToStatus(err)
|
||||||
@ -257,10 +257,10 @@ func (fs *FS) Chmod(path string, mode uint32, context *fuse.Context) (code fuse.
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fuse.ToStatus(err)
|
return fuse.ToStatus(err)
|
||||||
}
|
}
|
||||||
defer dirfd.Close()
|
defer syscall.Close(dirfd)
|
||||||
// os.Chmod goes through the "syscallMode" translation function that messes
|
// os.Chmod goes through the "syscallMode" translation function that messes
|
||||||
// up the suid and sgid bits. So use a syscall directly.
|
// up the suid and sgid bits. So use a syscall directly.
|
||||||
err = syscallcompat.Fchmodat(int(dirfd.Fd()), cName, mode, unix.AT_SYMLINK_NOFOLLOW)
|
err = syscallcompat.Fchmodat(dirfd, cName, mode, unix.AT_SYMLINK_NOFOLLOW)
|
||||||
return fuse.ToStatus(err)
|
return fuse.ToStatus(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -273,8 +273,8 @@ func (fs *FS) Chown(path string, uid uint32, gid uint32, context *fuse.Context)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fuse.ToStatus(err)
|
return fuse.ToStatus(err)
|
||||||
}
|
}
|
||||||
defer dirfd.Close()
|
defer syscall.Close(dirfd)
|
||||||
code = fuse.ToStatus(syscallcompat.Fchownat(int(dirfd.Fd()), cName, int(uid), int(gid), unix.AT_SYMLINK_NOFOLLOW))
|
code = fuse.ToStatus(syscallcompat.Fchownat(dirfd, cName, int(uid), int(gid), unix.AT_SYMLINK_NOFOLLOW))
|
||||||
if !code.Ok() {
|
if !code.Ok() {
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
@ -284,7 +284,7 @@ func (fs *FS) Chown(path string, uid uint32, gid uint32, context *fuse.Context)
|
|||||||
// Instead of checking if "cName" is a directory, we just blindly
|
// Instead of checking if "cName" is a directory, we just blindly
|
||||||
// execute the chown on "cName/gocryptfs.diriv" and ignore errors.
|
// execute the chown on "cName/gocryptfs.diriv" and ignore errors.
|
||||||
dirIVPath := filepath.Join(cName, nametransform.DirIVFilename)
|
dirIVPath := filepath.Join(cName, nametransform.DirIVFilename)
|
||||||
syscallcompat.Fchownat(int(dirfd.Fd()), dirIVPath, int(uid), int(gid), unix.AT_SYMLINK_NOFOLLOW)
|
syscallcompat.Fchownat(dirfd, dirIVPath, int(uid), int(gid), unix.AT_SYMLINK_NOFOLLOW)
|
||||||
}
|
}
|
||||||
return fuse.OK
|
return fuse.OK
|
||||||
}
|
}
|
||||||
@ -298,7 +298,7 @@ func (fs *FS) Mknod(path string, mode uint32, dev uint32, context *fuse.Context)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fuse.ToStatus(err)
|
return fuse.ToStatus(err)
|
||||||
}
|
}
|
||||||
defer dirfd.Close()
|
defer syscall.Close(dirfd)
|
||||||
// Create ".name" file to store long file name (except in PlaintextNames mode)
|
// Create ".name" file to store long file name (except in PlaintextNames mode)
|
||||||
if !fs.args.PlaintextNames && nametransform.IsLongContent(cName) {
|
if !fs.args.PlaintextNames && nametransform.IsLongContent(cName) {
|
||||||
err = fs.nameTransform.WriteLongName(dirfd, cName, path)
|
err = fs.nameTransform.WriteLongName(dirfd, cName, path)
|
||||||
@ -306,20 +306,20 @@ func (fs *FS) Mknod(path string, mode uint32, dev uint32, context *fuse.Context)
|
|||||||
return fuse.ToStatus(err)
|
return fuse.ToStatus(err)
|
||||||
}
|
}
|
||||||
// Create "gocryptfs.longfile." device node
|
// Create "gocryptfs.longfile." device node
|
||||||
err = syscallcompat.Mknodat(int(dirfd.Fd()), cName, mode, int(dev))
|
err = syscallcompat.Mknodat(dirfd, cName, mode, int(dev))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
nametransform.DeleteLongName(dirfd, cName)
|
nametransform.DeleteLongName(dirfd, cName)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Create regular device node
|
// Create regular device node
|
||||||
err = syscallcompat.Mknodat(int(dirfd.Fd()), cName, mode, int(dev))
|
err = syscallcompat.Mknodat(dirfd, cName, mode, int(dev))
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fuse.ToStatus(err)
|
return fuse.ToStatus(err)
|
||||||
}
|
}
|
||||||
// Set owner
|
// Set owner
|
||||||
if fs.args.PreserveOwner {
|
if fs.args.PreserveOwner {
|
||||||
err = syscallcompat.Fchownat(int(dirfd.Fd()), cName, int(context.Owner.Uid),
|
err = syscallcompat.Fchownat(dirfd, cName, int(context.Owner.Uid),
|
||||||
int(context.Owner.Gid), unix.AT_SYMLINK_NOFOLLOW)
|
int(context.Owner.Gid), unix.AT_SYMLINK_NOFOLLOW)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tlog.Warn.Printf("Mknod: Fchownat failed: %v", err)
|
tlog.Warn.Printf("Mknod: Fchownat failed: %v", err)
|
||||||
@ -416,9 +416,9 @@ func (fs *FS) Unlink(path string, context *fuse.Context) (code fuse.Status) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fuse.ToStatus(err)
|
return fuse.ToStatus(err)
|
||||||
}
|
}
|
||||||
defer dirfd.Close()
|
defer syscall.Close(dirfd)
|
||||||
// Delete content
|
// Delete content
|
||||||
err = syscallcompat.Unlinkat(int(dirfd.Fd()), cName, 0)
|
err = syscallcompat.Unlinkat(dirfd, cName, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fuse.ToStatus(err)
|
return fuse.ToStatus(err)
|
||||||
}
|
}
|
||||||
@ -454,7 +454,7 @@ func (fs *FS) Symlink(target string, linkName string, context *fuse.Context) (co
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fuse.ToStatus(err)
|
return fuse.ToStatus(err)
|
||||||
}
|
}
|
||||||
defer dirfd.Close()
|
defer syscall.Close(dirfd)
|
||||||
cTarget := target
|
cTarget := target
|
||||||
if !fs.args.PlaintextNames {
|
if !fs.args.PlaintextNames {
|
||||||
// Symlinks are encrypted like file contents (GCM) and base64-encoded
|
// Symlinks are encrypted like file contents (GCM) and base64-encoded
|
||||||
@ -467,20 +467,20 @@ func (fs *FS) Symlink(target string, linkName string, context *fuse.Context) (co
|
|||||||
return fuse.ToStatus(err)
|
return fuse.ToStatus(err)
|
||||||
}
|
}
|
||||||
// Create "gocryptfs.longfile." symlink
|
// Create "gocryptfs.longfile." symlink
|
||||||
err = syscallcompat.Symlinkat(cTarget, int(dirfd.Fd()), cName)
|
err = syscallcompat.Symlinkat(cTarget, dirfd, cName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
nametransform.DeleteLongName(dirfd, cName)
|
nametransform.DeleteLongName(dirfd, cName)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Create symlink
|
// Create symlink
|
||||||
err = syscallcompat.Symlinkat(cTarget, int(dirfd.Fd()), cName)
|
err = syscallcompat.Symlinkat(cTarget, dirfd, cName)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fuse.ToStatus(err)
|
return fuse.ToStatus(err)
|
||||||
}
|
}
|
||||||
// Set owner
|
// Set owner
|
||||||
if fs.args.PreserveOwner {
|
if fs.args.PreserveOwner {
|
||||||
err = syscallcompat.Fchownat(int(dirfd.Fd()), cName, int(context.Owner.Uid),
|
err = syscallcompat.Fchownat(dirfd, cName, int(context.Owner.Uid),
|
||||||
int(context.Owner.Gid), unix.AT_SYMLINK_NOFOLLOW)
|
int(context.Owner.Gid), unix.AT_SYMLINK_NOFOLLOW)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tlog.Warn.Printf("Symlink: Fchownat failed: %v", err)
|
tlog.Warn.Printf("Symlink: Fchownat failed: %v", err)
|
||||||
@ -510,32 +510,32 @@ func (fs *FS) Rename(oldPath string, newPath string, context *fuse.Context) (cod
|
|||||||
return fuse.ToStatus(syscall.Rename(cOldPath, cNewPath))
|
return fuse.ToStatus(syscall.Rename(cOldPath, cNewPath))
|
||||||
}
|
}
|
||||||
// Handle long source file name
|
// Handle long source file name
|
||||||
var oldDirFd *os.File
|
oldDirFd := -1
|
||||||
var finalOldDirFd int
|
finalOldDirFd := -1
|
||||||
var finalOldPath = cOldPath
|
var finalOldPath = cOldPath
|
||||||
cOldName := filepath.Base(cOldPath)
|
cOldName := filepath.Base(cOldPath)
|
||||||
if nametransform.IsLongContent(cOldName) {
|
if nametransform.IsLongContent(cOldName) {
|
||||||
oldDirFd, err = os.Open(filepath.Dir(cOldPath))
|
oldDirFd, err = syscall.Open(filepath.Dir(cOldPath), syscall.O_RDONLY|syscall.O_DIRECTORY, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fuse.ToStatus(err)
|
return fuse.ToStatus(err)
|
||||||
}
|
}
|
||||||
defer oldDirFd.Close()
|
defer syscall.Close(oldDirFd)
|
||||||
finalOldDirFd = int(oldDirFd.Fd())
|
finalOldDirFd = oldDirFd
|
||||||
// Use relative path
|
// Use relative path
|
||||||
finalOldPath = cOldName
|
finalOldPath = cOldName
|
||||||
}
|
}
|
||||||
// Handle long destination file name
|
// Handle long destination file name
|
||||||
var newDirFd *os.File
|
newDirFd := -1
|
||||||
var finalNewDirFd int
|
finalNewDirFd := -1
|
||||||
var finalNewPath = cNewPath
|
finalNewPath := cNewPath
|
||||||
cNewName := filepath.Base(cNewPath)
|
cNewName := filepath.Base(cNewPath)
|
||||||
if nametransform.IsLongContent(cNewName) {
|
if nametransform.IsLongContent(cNewName) {
|
||||||
newDirFd, err = os.Open(filepath.Dir(cNewPath))
|
newDirFd, err = syscall.Open(filepath.Dir(cNewPath), syscall.O_RDONLY|syscall.O_DIRECTORY, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fuse.ToStatus(err)
|
return fuse.ToStatus(err)
|
||||||
}
|
}
|
||||||
defer newDirFd.Close()
|
defer syscall.Close(newDirFd)
|
||||||
finalNewDirFd = int(newDirFd.Fd())
|
finalNewDirFd = newDirFd
|
||||||
// Use relative path
|
// Use relative path
|
||||||
finalNewPath = cNewName
|
finalNewPath = cNewName
|
||||||
// Create destination .name file
|
// Create destination .name file
|
||||||
@ -545,7 +545,7 @@ func (fs *FS) Rename(oldPath string, newPath string, context *fuse.Context) (cod
|
|||||||
// file anyway. We still set newDirFd to nil to ensure that we do not delete
|
// file anyway. We still set newDirFd to nil to ensure that we do not delete
|
||||||
// the file on error.
|
// the file on error.
|
||||||
if err == syscall.EEXIST {
|
if err == syscall.EEXIST {
|
||||||
newDirFd = nil
|
newDirFd = -1
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return fuse.ToStatus(err)
|
return fuse.ToStatus(err)
|
||||||
}
|
}
|
||||||
@ -565,13 +565,13 @@ func (fs *FS) Rename(oldPath string, newPath string, context *fuse.Context) (cod
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if newDirFd != nil {
|
if newDirFd >= 0 {
|
||||||
// Roll back .name creation
|
// Roll back .name creation
|
||||||
nametransform.DeleteLongName(newDirFd, cNewName)
|
nametransform.DeleteLongName(newDirFd, cNewName)
|
||||||
}
|
}
|
||||||
return fuse.ToStatus(err)
|
return fuse.ToStatus(err)
|
||||||
}
|
}
|
||||||
if oldDirFd != nil {
|
if oldDirFd >= 0 {
|
||||||
nametransform.DeleteLongName(oldDirFd, cOldName)
|
nametransform.DeleteLongName(oldDirFd, cOldName)
|
||||||
}
|
}
|
||||||
return fuse.OK
|
return fuse.OK
|
||||||
@ -586,12 +586,12 @@ func (fs *FS) Link(oldPath string, newPath string, context *fuse.Context) (code
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fuse.ToStatus(err)
|
return fuse.ToStatus(err)
|
||||||
}
|
}
|
||||||
defer oldDirFd.Close()
|
defer syscall.Close(oldDirFd)
|
||||||
newDirFd, cNewName, err := fs.openBackingDir(newPath)
|
newDirFd, cNewName, err := fs.openBackingDir(newPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fuse.ToStatus(err)
|
return fuse.ToStatus(err)
|
||||||
}
|
}
|
||||||
defer newDirFd.Close()
|
defer syscall.Close(newDirFd)
|
||||||
// Handle long file name (except in PlaintextNames mode)
|
// Handle long file name (except in PlaintextNames mode)
|
||||||
if !fs.args.PlaintextNames && nametransform.IsLongContent(cNewName) {
|
if !fs.args.PlaintextNames && nametransform.IsLongContent(cNewName) {
|
||||||
err = fs.nameTransform.WriteLongName(newDirFd, cNewName, newPath)
|
err = fs.nameTransform.WriteLongName(newDirFd, cNewName, newPath)
|
||||||
@ -599,13 +599,13 @@ func (fs *FS) Link(oldPath string, newPath string, context *fuse.Context) (code
|
|||||||
return fuse.ToStatus(err)
|
return fuse.ToStatus(err)
|
||||||
}
|
}
|
||||||
// Create "gocryptfs.longfile." link
|
// Create "gocryptfs.longfile." link
|
||||||
err = syscallcompat.Linkat(int(oldDirFd.Fd()), cOldName, int(newDirFd.Fd()), cNewName, 0)
|
err = syscallcompat.Linkat(oldDirFd, cOldName, newDirFd, cNewName, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
nametransform.DeleteLongName(newDirFd, cNewName)
|
nametransform.DeleteLongName(newDirFd, cNewName)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Create regular link
|
// Create regular link
|
||||||
err = syscallcompat.Linkat(int(oldDirFd.Fd()), cOldName, int(newDirFd.Fd()), cNewName, 0)
|
err = syscallcompat.Linkat(oldDirFd, cOldName, newDirFd, cNewName, 0)
|
||||||
}
|
}
|
||||||
return fuse.ToStatus(err)
|
return fuse.ToStatus(err)
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ const dsStoreName = ".DS_Store"
|
|||||||
// mkdirWithIv - create a new directory and corresponding diriv file. dirfd
|
// mkdirWithIv - create a new directory and corresponding diriv file. dirfd
|
||||||
// should be a handle to the parent directory, cName is the name of the new
|
// should be a handle to the parent directory, cName is the name of the new
|
||||||
// directory and mode specifies the access permissions to use.
|
// directory and mode specifies the access permissions to use.
|
||||||
func (fs *FS) mkdirWithIv(dirfd *os.File, cName string, mode uint32) error {
|
func (fs *FS) mkdirWithIv(dirfd int, cName string, mode uint32) error {
|
||||||
// Between the creation of the directory and the creation of gocryptfs.diriv
|
// Between the creation of the directory and the creation of gocryptfs.diriv
|
||||||
// the directory is inconsistent. Take the lock to prevent other readers
|
// the directory is inconsistent. Take the lock to prevent other readers
|
||||||
// from seeing it.
|
// from seeing it.
|
||||||
@ -34,14 +34,14 @@ func (fs *FS) mkdirWithIv(dirfd *os.File, cName string, mode uint32) error {
|
|||||||
// The new directory may take the place of an older one that is still in the cache
|
// The new directory may take the place of an older one that is still in the cache
|
||||||
fs.nameTransform.DirIVCache.Clear()
|
fs.nameTransform.DirIVCache.Clear()
|
||||||
defer fs.dirIVLock.Unlock()
|
defer fs.dirIVLock.Unlock()
|
||||||
err := syscallcompat.Mkdirat(int(dirfd.Fd()), cName, mode)
|
err := syscallcompat.Mkdirat(dirfd, cName, mode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Create gocryptfs.diriv
|
// Create gocryptfs.diriv
|
||||||
err = nametransform.WriteDirIV(dirfd, cName)
|
err = nametransform.WriteDirIV(dirfd, cName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err2 := syscallcompat.Unlinkat(int(dirfd.Fd()), cName, unix.AT_REMOVEDIR)
|
err2 := syscallcompat.Unlinkat(dirfd, cName, unix.AT_REMOVEDIR)
|
||||||
if err2 != nil {
|
if err2 != nil {
|
||||||
tlog.Warn.Printf("mkdirWithIv: rollback failed: %v", err2)
|
tlog.Warn.Printf("mkdirWithIv: rollback failed: %v", err2)
|
||||||
}
|
}
|
||||||
@ -58,12 +58,12 @@ func (fs *FS) Mkdir(newPath string, mode uint32, context *fuse.Context) (code fu
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fuse.ToStatus(err)
|
return fuse.ToStatus(err)
|
||||||
}
|
}
|
||||||
defer dirfd.Close()
|
defer syscall.Close(dirfd)
|
||||||
if fs.args.PlaintextNames {
|
if fs.args.PlaintextNames {
|
||||||
err = syscallcompat.Mkdirat(int(dirfd.Fd()), cName, mode)
|
err = syscallcompat.Mkdirat(dirfd, cName, mode)
|
||||||
// Set owner
|
// Set owner
|
||||||
if fs.args.PreserveOwner {
|
if fs.args.PreserveOwner {
|
||||||
err = syscallcompat.Fchownat(int(dirfd.Fd()), cName, int(context.Owner.Uid),
|
err = syscallcompat.Fchownat(dirfd, cName, int(context.Owner.Uid),
|
||||||
int(context.Owner.Gid), unix.AT_SYMLINK_NOFOLLOW)
|
int(context.Owner.Gid), unix.AT_SYMLINK_NOFOLLOW)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tlog.Warn.Printf("Mkdir: Fchownat failed: %v", err)
|
tlog.Warn.Printf("Mkdir: Fchownat failed: %v", err)
|
||||||
@ -98,19 +98,19 @@ func (fs *FS) Mkdir(newPath string, mode uint32, context *fuse.Context) (code fu
|
|||||||
}
|
}
|
||||||
// Set permissions back to what the user wanted
|
// Set permissions back to what the user wanted
|
||||||
if origMode != mode {
|
if origMode != mode {
|
||||||
err = syscallcompat.Fchmodat(int(dirfd.Fd()), cName, origMode, unix.AT_SYMLINK_NOFOLLOW)
|
err = syscallcompat.Fchmodat(dirfd, cName, origMode, unix.AT_SYMLINK_NOFOLLOW)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tlog.Warn.Printf("Mkdir: Fchmodat failed: %v", err)
|
tlog.Warn.Printf("Mkdir: Fchmodat failed: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Set owner
|
// Set owner
|
||||||
if fs.args.PreserveOwner {
|
if fs.args.PreserveOwner {
|
||||||
err = syscallcompat.Fchownat(int(dirfd.Fd()), cName, int(context.Owner.Uid),
|
err = syscallcompat.Fchownat(dirfd, cName, int(context.Owner.Uid),
|
||||||
int(context.Owner.Gid), unix.AT_SYMLINK_NOFOLLOW)
|
int(context.Owner.Gid), unix.AT_SYMLINK_NOFOLLOW)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tlog.Warn.Printf("Mkdir: Fchownat 1 failed: %v", err)
|
tlog.Warn.Printf("Mkdir: Fchownat 1 failed: %v", err)
|
||||||
}
|
}
|
||||||
err = syscallcompat.Fchownat(int(dirfd.Fd()), filepath.Join(cName, nametransform.DirIVFilename),
|
err = syscallcompat.Fchownat(dirfd, filepath.Join(cName, nametransform.DirIVFilename),
|
||||||
int(context.Owner.Uid), int(context.Owner.Gid), unix.AT_SYMLINK_NOFOLLOW)
|
int(context.Owner.Uid), int(context.Owner.Gid), unix.AT_SYMLINK_NOFOLLOW)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tlog.Warn.Printf("Mkdir: Fchownat 2 failed: %v", err)
|
tlog.Warn.Printf("Mkdir: Fchownat 2 failed: %v", err)
|
||||||
@ -120,9 +120,9 @@ func (fs *FS) Mkdir(newPath string, mode uint32, context *fuse.Context) (code fu
|
|||||||
}
|
}
|
||||||
|
|
||||||
// haveDsstore return true if one of the entries in "names" is ".DS_Store".
|
// haveDsstore return true if one of the entries in "names" is ".DS_Store".
|
||||||
func haveDsstore(names []string) bool {
|
func haveDsstore(entries []fuse.DirEntry) bool {
|
||||||
for _, n := range names {
|
for _, e := range entries {
|
||||||
if n == dsStoreName {
|
if e.Name == dsStoreName {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -140,14 +140,14 @@ func (fs *FS) Rmdir(path string, context *fuse.Context) (code fuse.Status) {
|
|||||||
return fuse.ToStatus(err)
|
return fuse.ToStatus(err)
|
||||||
}
|
}
|
||||||
parentDir := filepath.Dir(cPath)
|
parentDir := filepath.Dir(cPath)
|
||||||
parentDirFd, err := os.Open(parentDir)
|
parentDirFd, err := syscall.Open(parentDir, syscall.O_RDONLY|syscall.O_DIRECTORY, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fuse.ToStatus(err)
|
return fuse.ToStatus(err)
|
||||||
}
|
}
|
||||||
defer parentDirFd.Close()
|
defer syscall.Close(parentDirFd)
|
||||||
|
|
||||||
cName := filepath.Base(cPath)
|
cName := filepath.Base(cPath)
|
||||||
dirfdRaw, err := syscallcompat.Openat(int(parentDirFd.Fd()), cName,
|
dirfd, err := syscallcompat.Openat(parentDirFd, cName,
|
||||||
syscall.O_RDONLY|syscall.O_NOFOLLOW, 0)
|
syscall.O_RDONLY|syscall.O_NOFOLLOW, 0)
|
||||||
if err == syscall.EACCES {
|
if err == syscall.EACCES {
|
||||||
// We need permission to read and modify the directory
|
// We need permission to read and modify the directory
|
||||||
@ -169,7 +169,7 @@ func (fs *FS) Rmdir(path string, context *fuse.Context) (code fuse.Status) {
|
|||||||
// Retry open
|
// Retry open
|
||||||
var st syscall.Stat_t
|
var st syscall.Stat_t
|
||||||
syscall.Lstat(cPath, &st)
|
syscall.Lstat(cPath, &st)
|
||||||
dirfdRaw, err = syscallcompat.Openat(int(parentDirFd.Fd()), cName,
|
dirfd, err = syscallcompat.Openat(parentDirFd, cName,
|
||||||
syscall.O_RDONLY|syscall.O_NOFOLLOW, 0)
|
syscall.O_RDONLY|syscall.O_NOFOLLOW, 0)
|
||||||
// Undo the chmod if removing the directory failed
|
// Undo the chmod if removing the directory failed
|
||||||
defer func() {
|
defer func() {
|
||||||
@ -185,11 +185,10 @@ func (fs *FS) Rmdir(path string, context *fuse.Context) (code fuse.Status) {
|
|||||||
tlog.Debug.Printf("Rmdir: Open: %v", err)
|
tlog.Debug.Printf("Rmdir: Open: %v", err)
|
||||||
return fuse.ToStatus(err)
|
return fuse.ToStatus(err)
|
||||||
}
|
}
|
||||||
dirfd := os.NewFile(uintptr(dirfdRaw), cName)
|
defer syscall.Close(dirfd)
|
||||||
defer dirfd.Close()
|
|
||||||
retry:
|
retry:
|
||||||
// Check directory contents
|
// Check directory contents
|
||||||
children, err := dirfd.Readdirnames(10)
|
children, err := syscallcompat.Getdents(dirfd)
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
// The directory is empty
|
// The directory is empty
|
||||||
tlog.Warn.Printf("Rmdir: %q: gocryptfs.diriv is missing", cPath)
|
tlog.Warn.Printf("Rmdir: %q: gocryptfs.diriv is missing", cPath)
|
||||||
@ -223,27 +222,27 @@ retry:
|
|||||||
// Protect against concurrent readers.
|
// Protect against concurrent readers.
|
||||||
fs.dirIVLock.Lock()
|
fs.dirIVLock.Lock()
|
||||||
defer fs.dirIVLock.Unlock()
|
defer fs.dirIVLock.Unlock()
|
||||||
err = syscallcompat.Renameat(int(dirfd.Fd()), nametransform.DirIVFilename,
|
err = syscallcompat.Renameat(dirfd, nametransform.DirIVFilename,
|
||||||
int(parentDirFd.Fd()), tmpName)
|
parentDirFd, tmpName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tlog.Warn.Printf("Rmdir: Renaming %s to %s failed: %v",
|
tlog.Warn.Printf("Rmdir: Renaming %s to %s failed: %v",
|
||||||
nametransform.DirIVFilename, tmpName, err)
|
nametransform.DirIVFilename, tmpName, err)
|
||||||
return fuse.ToStatus(err)
|
return fuse.ToStatus(err)
|
||||||
}
|
}
|
||||||
// Actual Rmdir
|
// Actual Rmdir
|
||||||
err = syscallcompat.Unlinkat(int(parentDirFd.Fd()), cName, unix.AT_REMOVEDIR)
|
err = syscallcompat.Unlinkat(parentDirFd, cName, unix.AT_REMOVEDIR)
|
||||||
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
|
||||||
err2 := syscallcompat.Renameat(int(parentDirFd.Fd()), tmpName,
|
err2 := syscallcompat.Renameat(parentDirFd, tmpName,
|
||||||
int(dirfd.Fd()), nametransform.DirIVFilename)
|
dirfd, nametransform.DirIVFilename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tlog.Warn.Printf("Rmdir: Rename rollback failed: %v", err2)
|
tlog.Warn.Printf("Rmdir: Rename rollback failed: %v", err2)
|
||||||
}
|
}
|
||||||
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, 0)
|
err = syscallcompat.Unlinkat(parentDirFd, 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)
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ package fusefrontend
|
|||||||
// This file forwards file encryption operations to cryptfs
|
// This file forwards file encryption operations to cryptfs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/rfjakob/gocryptfs/internal/configfile"
|
"github.com/rfjakob/gocryptfs/internal/configfile"
|
||||||
@ -45,17 +44,17 @@ func (fs *FS) getBackingPath(relPath string) (string, error) {
|
|||||||
// "relPath" and returns the dirfd and the encrypted basename.
|
// "relPath" and returns the dirfd and the encrypted basename.
|
||||||
// The caller should then use Openat(dirfd, cName, ...) and friends.
|
// The caller should then use Openat(dirfd, cName, ...) and friends.
|
||||||
// openBackingDir is secure against symlink races.
|
// openBackingDir is secure against symlink races.
|
||||||
func (fs *FS) openBackingDir(relPath string) (*os.File, string, error) {
|
func (fs *FS) openBackingDir(relPath string) (int, string, error) {
|
||||||
cRelPath, err := fs.encryptPath(relPath)
|
cRelPath, err := fs.encryptPath(relPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, "", err
|
return -1, "", err
|
||||||
}
|
}
|
||||||
// Open parent dir
|
// Open parent dir
|
||||||
dirfd, err := syscallcompat.OpenDirNofollow(fs.args.Cipherdir, filepath.Dir(cRelPath))
|
dirfd, err := syscallcompat.OpenDirNofollow(fs.args.Cipherdir, filepath.Dir(cRelPath))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, "", err
|
return -1, "", err
|
||||||
}
|
}
|
||||||
return os.NewFile(uintptr(dirfd), cRelPath), filepath.Base(cRelPath), nil
|
return dirfd, filepath.Base(cRelPath), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// encryptPath - encrypt relative plaintext path
|
// encryptPath - encrypt relative plaintext path
|
||||||
|
@ -44,8 +44,8 @@ func ReadDirIV(dir string) (iv []byte, err error) {
|
|||||||
|
|
||||||
// ReadDirIVAt reads "gocryptfs.diriv" from the directory that is opened as "dirfd".
|
// ReadDirIVAt reads "gocryptfs.diriv" from the directory that is opened as "dirfd".
|
||||||
// Using the dirfd makes it immune to concurrent renames of the directory.
|
// Using the dirfd makes it immune to concurrent renames of the directory.
|
||||||
func ReadDirIVAt(dirfd *os.File) (iv []byte, err error) {
|
func ReadDirIVAt(dirfd int) (iv []byte, err error) {
|
||||||
fdRaw, err := syscallcompat.Openat(int(dirfd.Fd()), DirIVFilename,
|
fdRaw, err := syscallcompat.Openat(dirfd, DirIVFilename,
|
||||||
syscall.O_RDONLY|syscall.O_NOFOLLOW, 0)
|
syscall.O_RDONLY|syscall.O_NOFOLLOW, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("openat failed: %v", err)
|
return nil, fmt.Errorf("openat failed: %v", err)
|
||||||
@ -82,16 +82,16 @@ func fdReadDirIV(fd *os.File) (iv []byte, err error) {
|
|||||||
// "dir" should be a path (without slashes) relative to the directory
|
// "dir" should be a path (without slashes) relative to the directory
|
||||||
// described by "dirfd". This function is exported because it is used from
|
// described by "dirfd". This function is exported because it is used from
|
||||||
// pathfs_frontend, main, and also the automated tests.
|
// pathfs_frontend, main, and also the automated tests.
|
||||||
func WriteDirIV(dirfd *os.File, dir string) error {
|
func WriteDirIV(dirfd int, dir string) error {
|
||||||
// For relative paths we do not expect that "dir" contains slashes
|
// For relative paths we do not expect that "dir" contains slashes
|
||||||
if dirfd != nil && strings.Contains(dir, "/") {
|
if dirfd >= 0 && strings.Contains(dir, "/") {
|
||||||
log.Panicf("WriteDirIV: Relative path should not contain slashes: %v", dir)
|
log.Panicf("WriteDirIV: Relative path should not contain slashes: %v", dir)
|
||||||
}
|
}
|
||||||
iv := cryptocore.RandBytes(DirIVLen)
|
iv := cryptocore.RandBytes(DirIVLen)
|
||||||
file := filepath.Join(dir, DirIVFilename)
|
file := filepath.Join(dir, DirIVFilename)
|
||||||
// 0400 permissions: gocryptfs.diriv should never be modified after creation.
|
// 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
|
// Don't use "ioutil.WriteFile", it causes trouble on NFS: https://github.com/rfjakob/gocryptfs/issues/105
|
||||||
fdRaw, err := syscallcompat.Openat(int(dirfd.Fd()), file, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0400)
|
fdRaw, err := syscallcompat.Openat(dirfd, file, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0400)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tlog.Warn.Printf("WriteDirIV: Openat: %v", err)
|
tlog.Warn.Printf("WriteDirIV: Openat: %v", err)
|
||||||
return err
|
return err
|
||||||
@ -105,14 +105,14 @@ func WriteDirIV(dirfd *os.File, dir string) error {
|
|||||||
tlog.Warn.Printf("WriteDirIV: Write: %v", err)
|
tlog.Warn.Printf("WriteDirIV: Write: %v", err)
|
||||||
}
|
}
|
||||||
// Delete incomplete gocryptfs.diriv file
|
// Delete incomplete gocryptfs.diriv file
|
||||||
syscallcompat.Unlinkat(int(dirfd.Fd()), file, 0)
|
syscallcompat.Unlinkat(dirfd, file, 0)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = fd.Close()
|
err = fd.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tlog.Warn.Printf("WriteDirIV: Close: %v", err)
|
tlog.Warn.Printf("WriteDirIV: Close: %v", err)
|
||||||
// Delete incomplete gocryptfs.diriv file
|
// Delete incomplete gocryptfs.diriv file
|
||||||
syscallcompat.Unlinkat(int(dirfd.Fd()), file, 0)
|
syscallcompat.Unlinkat(dirfd, file, 0)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -89,8 +89,8 @@ 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 int, hashName string) error {
|
||||||
err := syscallcompat.Unlinkat(int(dirfd.Fd()), hashName+LongNameSuffix, 0)
|
err := syscallcompat.Unlinkat(dirfd, hashName+LongNameSuffix, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tlog.Warn.Printf("DeleteLongName: %v", err)
|
tlog.Warn.Printf("DeleteLongName: %v", err)
|
||||||
}
|
}
|
||||||
@ -100,7 +100,7 @@ func DeleteLongName(dirfd *os.File, hashName string) error {
|
|||||||
// WriteLongName encrypts plainName and writes it into "hashName.name".
|
// WriteLongName encrypts plainName and writes it into "hashName.name".
|
||||||
// For the convenience of the caller, plainName may also be a path and will be
|
// For the convenience of the caller, plainName may also be a path and will be
|
||||||
// converted internally.
|
// converted internally.
|
||||||
func (n *NameTransform) WriteLongName(dirfd *os.File, hashName string, plainName string) (err error) {
|
func (n *NameTransform) WriteLongName(dirfd int, hashName string, plainName string) (err error) {
|
||||||
plainName = filepath.Base(plainName)
|
plainName = filepath.Base(plainName)
|
||||||
|
|
||||||
// Encrypt the basename
|
// Encrypt the basename
|
||||||
@ -111,7 +111,7 @@ func (n *NameTransform) WriteLongName(dirfd *os.File, hashName string, plainName
|
|||||||
cName := n.EncryptName(plainName, dirIV)
|
cName := n.EncryptName(plainName, dirIV)
|
||||||
|
|
||||||
// Write the encrypted name into hashName.name
|
// Write the encrypted name into hashName.name
|
||||||
fdRaw, err := syscallcompat.Openat(int(dirfd.Fd()), hashName+LongNameSuffix,
|
fdRaw, err := syscallcompat.Openat(dirfd, hashName+LongNameSuffix,
|
||||||
syscall.O_WRONLY|syscall.O_CREAT|syscall.O_EXCL, 0600)
|
syscall.O_WRONLY|syscall.O_CREAT|syscall.O_EXCL, 0600)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Don't warn if the file already exists - this is allowed for renames
|
// Don't warn if the file already exists - this is allowed for renames
|
||||||
|
@ -110,7 +110,7 @@ func ResetTmpDir(createDirIV bool) {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
if createDirIV {
|
if createDirIV {
|
||||||
err = nametransform.WriteDirIV(nil, DefaultCipherDir)
|
err = nametransform.WriteDirIV(-1, DefaultCipherDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user