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) | 
