aboutsummaryrefslogtreecommitdiff
path: root/internal/fusefrontend
diff options
context:
space:
mode:
Diffstat (limited to 'internal/fusefrontend')
-rw-r--r--internal/fusefrontend/args.go2
-rw-r--r--internal/fusefrontend/file.go9
-rw-r--r--internal/fusefrontend/file_allocate_truncate.go76
-rw-r--r--internal/fusefrontend/fs.go24
-rw-r--r--internal/fusefrontend/fs_dir.go3
5 files changed, 72 insertions, 42 deletions
diff --git a/internal/fusefrontend/args.go b/internal/fusefrontend/args.go
index d0e1835..64ca899 100644
--- a/internal/fusefrontend/args.go
+++ b/internal/fusefrontend/args.go
@@ -4,7 +4,7 @@ import (
"github.com/rfjakob/gocryptfs/internal/cryptocore"
)
-// Container for arguments that are passed from main() to fusefrontend
+// Args is a container for arguments that are passed from main() to fusefrontend
type Args struct {
Masterkey []byte
Cipherdir string
diff --git a/internal/fusefrontend/file.go b/internal/fusefrontend/file.go
index a04b6af..ab025d3 100644
--- a/internal/fusefrontend/file.go
+++ b/internal/fusefrontend/file.go
@@ -45,6 +45,7 @@ type file struct {
loopbackFile nodefs.File
}
+// NewFile returns a new go-fuse File instance.
func NewFile(fd *os.File, writeOnly bool, contentEnc *contentenc.ContentEnc) (nodefs.File, fuse.Status) {
var st syscall.Stat_t
err := syscall.Fstat(int(fd.Fd()), &st)
@@ -80,7 +81,7 @@ func (f *file) SetInode(n *nodefs.Inode) {
//
// Returns io.EOF if the file is empty
func (f *file) readHeader() error {
- buf := make([]byte, contentenc.HEADER_LEN)
+ buf := make([]byte, contentenc.HeaderLen)
_, err := f.fd.ReadAt(buf, 0)
if err != nil {
return err
@@ -100,7 +101,7 @@ func (f *file) createHeader() error {
buf := h.Pack()
// Prevent partially written (=corrupt) header by preallocating the space beforehand
- err := syscallcompat.EnospcPrealloc(int(f.fd.Fd()), 0, contentenc.HEADER_LEN)
+ err := syscallcompat.EnospcPrealloc(int(f.fd.Fd()), 0, contentenc.HeaderLen)
if err != nil {
tlog.Warn.Printf("ino%d: createHeader: prealloc failed: %s\n", f.ino, err.Error())
return err
@@ -159,7 +160,7 @@ func (f *file) doRead(off uint64, length uint64) ([]byte, fuse.Status) {
tlog.Debug.Printf("ReadAt offset=%d bytes (%d blocks), want=%d, got=%d", alignedOffset, firstBlockNo, alignedLength, n)
// Decrypt it
- plaintext, err := f.contentEnc.DecryptBlocks(ciphertext, firstBlockNo, f.header.Id)
+ plaintext, err := f.contentEnc.DecryptBlocks(ciphertext, firstBlockNo, f.header.ID)
if err != nil {
curruptBlockNo := firstBlockNo + f.contentEnc.PlainOffToBlockNo(uint64(len(plaintext)))
cipherOff := f.contentEnc.BlockNoToCipherOff(curruptBlockNo)
@@ -256,7 +257,7 @@ func (f *file) doWrite(data []byte, off int64) (uint32, fuse.Status) {
// Encrypt
blockOffset := b.BlockCipherOff()
- blockData = f.contentEnc.EncryptBlock(blockData, b.BlockNo, f.header.Id)
+ blockData = f.contentEnc.EncryptBlock(blockData, b.BlockNo, f.header.ID)
tlog.Debug.Printf("ino%d: Writing %d bytes to block #%d",
f.ino, uint64(len(blockData))-f.contentEnc.BlockOverhead(), b.BlockNo)
diff --git a/internal/fusefrontend/file_allocate_truncate.go b/internal/fusefrontend/file_allocate_truncate.go
index f22fa4b..650e1db 100644
--- a/internal/fusefrontend/file_allocate_truncate.go
+++ b/internal/fusefrontend/file_allocate_truncate.go
@@ -14,7 +14,10 @@ import (
"github.com/rfjakob/gocryptfs/internal/tlog"
)
+// FALLOC_DEFAULT is a "normal" fallocate operation
const FALLOC_DEFAULT = 0x00
+
+// FALLOC_FL_KEEP_SIZE allocates disk space while not modifying the file size
const FALLOC_FL_KEEP_SIZE = 0x01
// Only warn once
@@ -116,11 +119,12 @@ func (f *file) Truncate(newSize uint64) fuse.Status {
oldSize, err := f.statPlainSize()
if err != nil {
return fuse.ToStatus(err)
- } else {
- oldB := float32(oldSize) / float32(f.contentEnc.PlainBS())
- newB := float32(newSize) / float32(f.contentEnc.PlainBS())
- tlog.Debug.Printf("ino%d: FUSE Truncate from %.2f to %.2f blocks (%d to %d bytes)", f.ino, oldB, newB, oldSize, newSize)
}
+
+ oldB := float32(oldSize) / float32(f.contentEnc.PlainBS())
+ newB := float32(newSize) / float32(f.contentEnc.PlainBS())
+ tlog.Debug.Printf("ino%d: FUSE Truncate from %.2f to %.2f blocks (%d to %d bytes)", f.ino, oldB, newB, oldSize, newSize)
+
// File size stays the same - nothing to do
if newSize == oldSize {
return fuse.OK
@@ -128,34 +132,34 @@ func (f *file) Truncate(newSize uint64) fuse.Status {
// File grows
if newSize > oldSize {
return f.truncateGrowFile(oldSize, newSize)
- } else {
- // File shrinks
- blockNo := f.contentEnc.PlainOffToBlockNo(newSize)
- cipherOff := f.contentEnc.BlockNoToCipherOff(blockNo)
- plainOff := f.contentEnc.BlockNoToPlainOff(blockNo)
- lastBlockLen := newSize - plainOff
- var data []byte
- if lastBlockLen > 0 {
- var status fuse.Status
- data, status = f.doRead(plainOff, lastBlockLen)
- if status != fuse.OK {
- tlog.Warn.Printf("Truncate: shrink doRead returned error: %v", err)
- return status
- }
- }
- // Truncate down to the last complete block
- err = syscall.Ftruncate(int(f.fd.Fd()), int64(cipherOff))
- if err != nil {
- tlog.Warn.Printf("Truncate: shrink Ftruncate returned error: %v", err)
- return fuse.ToStatus(err)
- }
- // Append partial block
- if lastBlockLen > 0 {
- _, status := f.doWrite(data, int64(plainOff))
+ }
+
+ // File shrinks
+ blockNo := f.contentEnc.PlainOffToBlockNo(newSize)
+ cipherOff := f.contentEnc.BlockNoToCipherOff(blockNo)
+ plainOff := f.contentEnc.BlockNoToPlainOff(blockNo)
+ lastBlockLen := newSize - plainOff
+ var data []byte
+ if lastBlockLen > 0 {
+ var status fuse.Status
+ data, status = f.doRead(plainOff, lastBlockLen)
+ if status != fuse.OK {
+ tlog.Warn.Printf("Truncate: shrink doRead returned error: %v", err)
return status
}
- return fuse.OK
}
+ // Truncate down to the last complete block
+ err = syscall.Ftruncate(int(f.fd.Fd()), int64(cipherOff))
+ if err != nil {
+ tlog.Warn.Printf("Truncate: shrink Ftruncate returned error: %v", err)
+ return fuse.ToStatus(err)
+ }
+ // Append partial block
+ if lastBlockLen > 0 {
+ _, status := f.doWrite(data, int64(plainOff))
+ return status
+ }
+ return fuse.OK
}
// statPlainSize stats the file and returns the plaintext size
@@ -198,12 +202,12 @@ func (f *file) truncateGrowFile(oldPlainSz uint64, newPlainSz uint64) fuse.Statu
off := lastBlock.BlockPlainOff()
_, status := f.doWrite(make([]byte, lastBlock.Length), int64(off+lastBlock.Skip))
return status
- } else {
- off := lastBlock.BlockCipherOff()
- err = syscall.Ftruncate(f.intFd(), int64(off+f.contentEnc.CipherBS()))
- if err != nil {
- tlog.Warn.Printf("Truncate: grow Ftruncate returned error: %v", err)
- }
- return fuse.ToStatus(err)
}
+
+ off := lastBlock.BlockCipherOff()
+ err = syscall.Ftruncate(f.intFd(), int64(off+f.contentEnc.CipherBS()))
+ if err != nil {
+ tlog.Warn.Printf("Truncate: grow Ftruncate returned error: %v", err)
+ }
+ return fuse.ToStatus(err)
}
diff --git a/internal/fusefrontend/fs.go b/internal/fusefrontend/fs.go
index 62146a2..26a5b5e 100644
--- a/internal/fusefrontend/fs.go
+++ b/internal/fusefrontend/fs.go
@@ -22,6 +22,7 @@ import (
"github.com/rfjakob/gocryptfs/internal/tlog"
)
+// FS implements the go-fuse virtual filesystem interface.
type FS struct {
pathfs.FileSystem // loopbackFileSystem, see go-fuse/fuse/pathfs/loopback.go
args Args // Stores configuration arguments
@@ -35,7 +36,9 @@ type FS struct {
contentEnc *contentenc.ContentEnc
}
-// Encrypted FUSE overlay filesystem
+var _ pathfs.FileSystem = &FS{} // Verify that interface is implemented.
+
+// NewFS returns a new encrypted FUSE overlay filesystem.
func NewFS(args Args) *FS {
cryptoCore := cryptocore.New(args.Masterkey, args.CryptoBackend, contentenc.DefaultIVBits)
contentEnc := contentenc.New(cryptoCore, contentenc.DefaultBS)
@@ -49,6 +52,7 @@ func NewFS(args Args) *FS {
}
}
+// GetAttr implements pathfs.Filesystem.
func (fs *FS) GetAttr(name string, context *fuse.Context) (*fuse.Attr, fuse.Status) {
tlog.Debug.Printf("FS.GetAttr('%s')", name)
if fs.isFiltered(name) {
@@ -85,6 +89,7 @@ func (fs *FS) mangleOpenFlags(flags uint32) (newFlags int, writeOnly bool) {
return newFlags, writeOnly
}
+// Open implements pathfs.Filesystem.
func (fs *FS) Open(path string, flags uint32, context *fuse.Context) (fuseFile nodefs.File, status fuse.Status) {
if fs.isFiltered(path) {
return nil, fuse.EPERM
@@ -104,6 +109,7 @@ func (fs *FS) Open(path string, flags uint32, context *fuse.Context) (fuseFile n
return NewFile(f, writeOnly, fs.contentEnc)
}
+// Create implements pathfs.Filesystem.
func (fs *FS) Create(path string, flags uint32, mode uint32, context *fuse.Context) (fuseFile nodefs.File, code fuse.Status) {
if fs.isFiltered(path) {
return nil, fuse.EPERM
@@ -156,6 +162,7 @@ func (fs *FS) Create(path string, flags uint32, mode uint32, context *fuse.Conte
return NewFile(fd, writeOnly, fs.contentEnc)
}
+// Chmod implements pathfs.Filesystem.
func (fs *FS) Chmod(path string, mode uint32, context *fuse.Context) (code fuse.Status) {
if fs.isFiltered(path) {
return fuse.EPERM
@@ -170,6 +177,7 @@ func (fs *FS) Chmod(path string, mode uint32, context *fuse.Context) (code fuse.
return fuse.ToStatus(err)
}
+// Chown implements pathfs.Filesystem.
func (fs *FS) Chown(path string, uid uint32, gid uint32, context *fuse.Context) (code fuse.Status) {
if fs.isFiltered(path) {
return fuse.EPERM
@@ -181,6 +189,7 @@ func (fs *FS) Chown(path string, uid uint32, gid uint32, context *fuse.Context)
return fuse.ToStatus(os.Lchown(cPath, int(uid), int(gid)))
}
+// Mknod implements pathfs.Filesystem.
func (fs *FS) Mknod(path string, mode uint32, dev uint32, context *fuse.Context) (code fuse.Status) {
if fs.isFiltered(path) {
return fuse.EPERM
@@ -217,6 +226,7 @@ func (fs *FS) Mknod(path string, mode uint32, dev uint32, context *fuse.Context)
return fs.FileSystem.Mknod(cPath, mode, dev, context)
}
+// Truncate implements pathfs.Filesystem.
// Support truncate(2) by opening the file and calling ftruncate(2)
// While the glibc "truncate" wrapper seems to always use ftruncate, fsstress from
// xfstests uses this a lot by calling "truncate64" directly.
@@ -230,6 +240,7 @@ func (fs *FS) Truncate(path string, offset uint64, context *fuse.Context) (code
return code
}
+// Utimens implements pathfs.Filesystem.
func (fs *FS) Utimens(path string, a *time.Time, m *time.Time, context *fuse.Context) (code fuse.Status) {
if fs.isFiltered(path) {
return fuse.EPERM
@@ -241,6 +252,7 @@ func (fs *FS) Utimens(path string, a *time.Time, m *time.Time, context *fuse.Con
return fs.FileSystem.Utimens(cPath, a, m, context)
}
+// StatFs implements pathfs.Filesystem.
func (fs *FS) StatFs(path string) *fuse.StatfsOut {
if fs.isFiltered(path) {
return nil
@@ -252,6 +264,7 @@ func (fs *FS) StatFs(path string) *fuse.StatfsOut {
return fs.FileSystem.StatFs(cPath)
}
+// Readlink implements pathfs.Filesystem.
func (fs *FS) Readlink(path string, context *fuse.Context) (out string, status fuse.Status) {
cPath, err := fs.getBackingPath(path)
if err != nil {
@@ -278,6 +291,7 @@ func (fs *FS) Readlink(path string, context *fuse.Context) (out string, status f
return string(target), fuse.OK
}
+// Unlink implements pathfs.Filesystem.
func (fs *FS) Unlink(path string, context *fuse.Context) (code fuse.Status) {
if fs.isFiltered(path) {
return fuse.EPERM
@@ -312,6 +326,7 @@ func (fs *FS) Unlink(path string, context *fuse.Context) (code fuse.Status) {
return fuse.ToStatus(err)
}
+// Symlink implements pathfs.Filesystem.
func (fs *FS) Symlink(target string, linkName string, context *fuse.Context) (code fuse.Status) {
tlog.Debug.Printf("Symlink(\"%s\", \"%s\")", target, linkName)
if fs.isFiltered(linkName) {
@@ -359,6 +374,7 @@ func (fs *FS) Symlink(target string, linkName string, context *fuse.Context) (co
return fuse.ToStatus(err)
}
+// Rename implements pathfs.Filesystem.
func (fs *FS) Rename(oldPath string, newPath string, context *fuse.Context) (code fuse.Status) {
if fs.isFiltered(newPath) {
return fuse.EPERM
@@ -437,6 +453,7 @@ func (fs *FS) Rename(oldPath string, newPath string, context *fuse.Context) (cod
return fuse.OK
}
+// Link implements pathfs.Filesystem.
func (fs *FS) Link(oldPath string, newPath string, context *fuse.Context) (code fuse.Status) {
if fs.isFiltered(newPath) {
return fuse.EPERM
@@ -474,6 +491,7 @@ func (fs *FS) Link(oldPath string, newPath string, context *fuse.Context) (code
return fuse.ToStatus(os.Link(cOldPath, cNewPath))
}
+// Access implements pathfs.Filesystem.
func (fs *FS) Access(path string, mode uint32, context *fuse.Context) (code fuse.Status) {
if fs.isFiltered(path) {
return fuse.EPERM
@@ -485,18 +503,22 @@ func (fs *FS) Access(path string, mode uint32, context *fuse.Context) (code fuse
return fuse.ToStatus(syscall.Access(cPath, mode))
}
+// GetXAttr implements pathfs.Filesystem.
func (fs *FS) GetXAttr(name string, attr string, context *fuse.Context) ([]byte, fuse.Status) {
return nil, fuse.ENOSYS
}
+// SetXAttr implements pathfs.Filesystem.
func (fs *FS) SetXAttr(name string, attr string, data []byte, flags int, context *fuse.Context) fuse.Status {
return fuse.ENOSYS
}
+// ListXAttr implements pathfs.Filesystem.
func (fs *FS) ListXAttr(name string, context *fuse.Context) ([]string, fuse.Status) {
return nil, fuse.ENOSYS
}
+// RemoveXAttr implements pathfs.Filesystem.
func (fs *FS) RemoveXAttr(name string, attr string, context *fuse.Context) fuse.Status {
return fuse.ENOSYS
}
diff --git a/internal/fusefrontend/fs_dir.go b/internal/fusefrontend/fs_dir.go
index ab97932..a3b2ccf 100644
--- a/internal/fusefrontend/fs_dir.go
+++ b/internal/fusefrontend/fs_dir.go
@@ -40,6 +40,7 @@ func (fs *FS) mkdirWithIv(cPath string, mode uint32) error {
return err
}
+// Mkdir implements pathfs.FileSystem
func (fs *FS) Mkdir(newPath string, mode uint32, context *fuse.Context) (code fuse.Status) {
if fs.isFiltered(newPath) {
return fuse.EPERM
@@ -97,6 +98,7 @@ func (fs *FS) Mkdir(newPath string, mode uint32, context *fuse.Context) (code fu
return fuse.OK
}
+// Rmdir implements pathfs.FileSystem
func (fs *FS) Rmdir(path string, context *fuse.Context) (code fuse.Status) {
cPath, err := fs.getBackingPath(path)
if err != nil {
@@ -215,6 +217,7 @@ func (fs *FS) Rmdir(path string, context *fuse.Context) (code fuse.Status) {
return fuse.OK
}
+// OpenDir implements pathfs.FileSystem
func (fs *FS) OpenDir(dirName string, context *fuse.Context) ([]fuse.DirEntry, fuse.Status) {
tlog.Debug.Printf("OpenDir(%s)", dirName)
cDirName, err := fs.encryptPath(dirName)