diff options
Diffstat (limited to 'internal/fusefrontend')
-rw-r--r-- | internal/fusefrontend/args.go | 2 | ||||
-rw-r--r-- | internal/fusefrontend/file.go | 9 | ||||
-rw-r--r-- | internal/fusefrontend/file_allocate_truncate.go | 76 | ||||
-rw-r--r-- | internal/fusefrontend/fs.go | 24 | ||||
-rw-r--r-- | internal/fusefrontend/fs_dir.go | 3 |
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) |