diff options
Diffstat (limited to 'pathfs_frontend')
| -rw-r--r-- | pathfs_frontend/file.go | 112 | ||||
| -rw-r--r-- | pathfs_frontend/file_holes.go | 13 | ||||
| -rw-r--r-- | pathfs_frontend/fs.go | 76 | ||||
| -rw-r--r-- | pathfs_frontend/fs_dir.go | 44 | ||||
| -rw-r--r-- | pathfs_frontend/names.go | 17 | 
5 files changed, 143 insertions, 119 deletions
| diff --git a/pathfs_frontend/file.go b/pathfs_frontend/file.go index 33ad0c7..387eb35 100644 --- a/pathfs_frontend/file.go +++ b/pathfs_frontend/file.go @@ -13,7 +13,9 @@ import (  	"github.com/hanwen/go-fuse/fuse"  	"github.com/hanwen/go-fuse/fuse/nodefs" -	"github.com/rfjakob/gocryptfs/cryptfs" + +	"github.com/rfjakob/gocryptfs/internal/contentenc" +	"github.com/rfjakob/gocryptfs/internal/toggledlog"  )  // File - based on loopbackFile in go-fuse/fuse/nodefs/files.go @@ -29,19 +31,19 @@ type file struct {  	// Was the file opened O_WRONLY?  	writeOnly bool -	// Parent CryptFS -	cfs *cryptfs.CryptFS +	// Content encryption helper +	contentEnc *contentenc.ContentEnc  	// Inode number  	ino uint64  	// File header -	header *cryptfs.FileHeader +	header *contentenc.FileHeader  	forgotten bool  } -func NewFile(fd *os.File, writeOnly bool, cfs *cryptfs.CryptFS) nodefs.File { +func NewFile(fd *os.File, writeOnly bool, contentEnc *contentenc.ContentEnc) nodefs.File {  	var st syscall.Stat_t  	syscall.Fstat(int(fd.Fd()), &st)  	wlock.register(st.Ino) @@ -49,7 +51,7 @@ func NewFile(fd *os.File, writeOnly bool, cfs *cryptfs.CryptFS) nodefs.File {  	return &file{  		fd:        fd,  		writeOnly: writeOnly, -		cfs:       cfs, +		contentEnc: contentEnc,  		ino:       st.Ino,  	}  } @@ -71,12 +73,12 @@ func (f *file) SetInode(n *nodefs.Inode) {  //  // Returns io.EOF if the file is empty  func (f *file) readHeader() error { -	buf := make([]byte, cryptfs.HEADER_LEN) +	buf := make([]byte, contentenc.HEADER_LEN)  	_, err := f.fd.ReadAt(buf, 0)  	if err != nil {  		return err  	} -	h, err := cryptfs.ParseHeader(buf) +	h, err := contentenc.ParseHeader(buf)  	if err != nil {  		return err  	} @@ -87,13 +89,13 @@ func (f *file) readHeader() error {  // createHeader - create a new random header and write it to disk  func (f *file) createHeader() error { -	h := cryptfs.RandomHeader() +	h := contentenc.RandomHeader()  	buf := h.Pack()  	// Prevent partially written (=corrupt) header by preallocating the space beforehand -	err := prealloc(int(f.fd.Fd()), 0, cryptfs.HEADER_LEN) +	err := prealloc(int(f.fd.Fd()), 0, contentenc.HEADER_LEN)  	if err != nil { -		cryptfs.Warn.Printf("ino%d: createHeader: prealloc failed: %s\n", f.ino, err.Error()) +		toggledlog.Warn.Printf("ino%d: createHeader: prealloc failed: %s\n", f.ino, err.Error())  		return err  	} @@ -133,29 +135,29 @@ func (f *file) doRead(off uint64, length uint64) ([]byte, fuse.Status) {  	}  	// Read the backing ciphertext in one go -	blocks := f.cfs.ExplodePlainRange(off, length) +	blocks := f.contentEnc.ExplodePlainRange(off, length)  	alignedOffset, alignedLength := blocks[0].JointCiphertextRange(blocks)  	skip := blocks[0].Skip -	cryptfs.Debug.Printf("JointCiphertextRange(%d, %d) -> %d, %d, %d", off, length, alignedOffset, alignedLength, skip) +	toggledlog.Debug.Printf("JointCiphertextRange(%d, %d) -> %d, %d, %d", off, length, alignedOffset, alignedLength, skip)  	ciphertext := make([]byte, int(alignedLength))  	n, err := f.fd.ReadAt(ciphertext, int64(alignedOffset))  	if err != nil && err != io.EOF { -		cryptfs.Warn.Printf("read: ReadAt: %s", err.Error()) +		toggledlog.Warn.Printf("read: ReadAt: %s", err.Error())  		return nil, fuse.ToStatus(err)  	}  	// Truncate ciphertext buffer down to actually read bytes  	ciphertext = ciphertext[0:n]  	firstBlockNo := blocks[0].BlockNo -	cryptfs.Debug.Printf("ReadAt offset=%d bytes (%d blocks), want=%d, got=%d", alignedOffset, firstBlockNo, alignedLength, n) +	toggledlog.Debug.Printf("ReadAt offset=%d bytes (%d blocks), want=%d, got=%d", alignedOffset, firstBlockNo, alignedLength, n)  	// Decrypt it -	plaintext, err := f.cfs.DecryptBlocks(ciphertext, firstBlockNo, f.header.Id) +	plaintext, err := f.contentEnc.DecryptBlocks(ciphertext, firstBlockNo, f.header.Id)  	if err != nil { -		curruptBlockNo := firstBlockNo + f.cfs.PlainOffToBlockNo(uint64(len(plaintext))) -		cipherOff := f.cfs.BlockNoToCipherOff(curruptBlockNo) -		plainOff := f.cfs.BlockNoToPlainOff(curruptBlockNo) -		cryptfs.Warn.Printf("ino%d: doRead: corrupt block #%d (plainOff=%d, cipherOff=%d)", +		curruptBlockNo := firstBlockNo + f.contentEnc.PlainOffToBlockNo(uint64(len(plaintext))) +		cipherOff := f.contentEnc.BlockNoToCipherOff(curruptBlockNo) +		plainOff := f.contentEnc.BlockNoToPlainOff(curruptBlockNo) +		toggledlog.Warn.Printf("ino%d: doRead: corrupt block #%d (plainOff=%d, cipherOff=%d)",  			f.ino, curruptBlockNo, plainOff, cipherOff)  		return nil, fuse.EIO  	} @@ -179,23 +181,23 @@ func (f *file) Read(buf []byte, off int64) (resultData fuse.ReadResult, code fus  	f.fdLock.RLock()  	defer f.fdLock.RUnlock() -	cryptfs.Debug.Printf("ino%d: FUSE Read: offset=%d length=%d", f.ino, len(buf), off) +	toggledlog.Debug.Printf("ino%d: FUSE Read: offset=%d length=%d", f.ino, len(buf), off)  	if f.writeOnly { -		cryptfs.Warn.Printf("ino%d: Tried to read from write-only file", f.ino) +		toggledlog.Warn.Printf("ino%d: Tried to read from write-only file", f.ino)  		return nil, fuse.EBADF  	}  	out, status := f.doRead(uint64(off), uint64(len(buf)))  	if status == fuse.EIO { -		cryptfs.Warn.Printf("ino%d: Read failed with EIO, offset=%d, length=%d", f.ino, len(buf), off) +		toggledlog.Warn.Printf("ino%d: Read failed with EIO, offset=%d, length=%d", f.ino, len(buf), off)  	}  	if status != fuse.OK {  		return nil, status  	} -	cryptfs.Debug.Printf("ino%d: Read: status %v, returning %d bytes", f.ino, status, len(out)) +	toggledlog.Debug.Printf("ino%d: Read: status %v, returning %d bytes", f.ino, status, len(out))  	return fuse.ReadResultData(out), status  } @@ -225,7 +227,7 @@ func (f *file) doWrite(data []byte, off int64) (uint32, fuse.Status) {  	var written uint32  	status := fuse.OK  	dataBuf := bytes.NewBuffer(data) -	blocks := f.cfs.ExplodePlainRange(uint64(off), uint64(len(data))) +	blocks := f.contentEnc.ExplodePlainRange(uint64(off), uint64(len(data)))  	for _, b := range blocks {  		blockData := dataBuf.Next(int(b.Length)) @@ -234,26 +236,26 @@ func (f *file) doWrite(data []byte, off int64) (uint32, fuse.Status) {  		if b.IsPartial() {  			// Read  			o, _ := b.PlaintextRange() -			oldData, status := f.doRead(o, f.cfs.PlainBS()) +			oldData, status := f.doRead(o, f.contentEnc.PlainBS())  			if status != fuse.OK { -				cryptfs.Warn.Printf("ino%d fh%d: RMW read failed: %s", f.ino, f.intFd(), status.String()) +				toggledlog.Warn.Printf("ino%d fh%d: RMW read failed: %s", f.ino, f.intFd(), status.String())  				return written, status  			}  			// Modify -			blockData = f.cfs.MergeBlocks(oldData, blockData, int(b.Skip)) -			cryptfs.Debug.Printf("len(oldData)=%d len(blockData)=%d", len(oldData), len(blockData)) +			blockData = f.contentEnc.MergeBlocks(oldData, blockData, int(b.Skip)) +			toggledlog.Debug.Printf("len(oldData)=%d len(blockData)=%d", len(oldData), len(blockData))  		}  		// Encrypt  		blockOffset, blockLen := b.CiphertextRange() -		blockData = f.cfs.EncryptBlock(blockData, b.BlockNo, f.header.Id) -		cryptfs.Debug.Printf("ino%d: Writing %d bytes to block #%d", -			f.ino, uint64(len(blockData))-f.cfs.BlockOverhead(), b.BlockNo) +		blockData = f.contentEnc.EncryptBlock(blockData, b.BlockNo, f.header.Id) +		toggledlog.Debug.Printf("ino%d: Writing %d bytes to block #%d", +			f.ino, uint64(len(blockData))-f.contentEnc.BlockOverhead(), b.BlockNo)  		// Prevent partially written (=corrupt) blocks by preallocating the space beforehand  		err := prealloc(int(f.fd.Fd()), int64(blockOffset), int64(blockLen))  		if err != nil { -			cryptfs.Warn.Printf("ino%d fh%d: doWrite: prealloc failed: %s", f.ino, f.intFd(), err.Error()) +			toggledlog.Warn.Printf("ino%d fh%d: doWrite: prealloc failed: %s", f.ino, f.intFd(), err.Error())  			status = fuse.ToStatus(err)  			break  		} @@ -262,7 +264,7 @@ func (f *file) doWrite(data []byte, off int64) (uint32, fuse.Status) {  		_, err = f.fd.WriteAt(blockData, int64(blockOffset))  		if err != nil { -			cryptfs.Warn.Printf("doWrite: Write failed: %s", err.Error()) +			toggledlog.Warn.Printf("doWrite: Write failed: %s", err.Error())  			status = fuse.ToStatus(err)  			break  		} @@ -278,18 +280,18 @@ func (f *file) Write(data []byte, off int64) (uint32, fuse.Status) {  	wlock.lock(f.ino)  	defer wlock.unlock(f.ino) -	cryptfs.Debug.Printf("ino%d: FUSE Write: offset=%d length=%d", f.ino, off, len(data)) +	toggledlog.Debug.Printf("ino%d: FUSE Write: offset=%d length=%d", f.ino, off, len(data))  	fi, err := f.fd.Stat()  	if err != nil { -		cryptfs.Warn.Printf("Write: Fstat failed: %v", err) +		toggledlog.Warn.Printf("Write: Fstat failed: %v", err)  		return 0, fuse.ToStatus(err)  	} -	plainSize := f.cfs.CipherSizeToPlainSize(uint64(fi.Size())) +	plainSize := f.contentEnc.CipherSizeToPlainSize(uint64(fi.Size()))  	if f.createsHole(plainSize, off) {  		status := f.zeroPad(plainSize)  		if status != fuse.OK { -			cryptfs.Warn.Printf("zeroPad returned error %v", status) +			toggledlog.Warn.Printf("zeroPad returned error %v", status)  			return 0, status  		}  	} @@ -337,14 +339,14 @@ func (f *file) Truncate(newSize uint64) fuse.Status {  	defer wlock.unlock(f.ino)  	if f.forgotten { -		cryptfs.Warn.Printf("ino%d fh%d: Truncate on forgotten file", f.ino, f.intFd()) +		toggledlog.Warn.Printf("ino%d fh%d: Truncate on forgotten file", f.ino, f.intFd())  	}  	// Common case first: Truncate to zero  	if newSize == 0 {  		err := syscall.Ftruncate(int(f.fd.Fd()), 0)  		if err != nil { -			cryptfs.Warn.Printf("ino%d fh%d: Ftruncate(fd, 0) returned error: %v", f.ino, f.intFd(), err) +			toggledlog.Warn.Printf("ino%d fh%d: Ftruncate(fd, 0) returned error: %v", f.ino, f.intFd(), err)  			return fuse.ToStatus(err)  		}  		// Truncate to zero kills the file header @@ -356,14 +358,14 @@ func (f *file) Truncate(newSize uint64) fuse.Status {  	// the file  	fi, err := f.fd.Stat()  	if err != nil { -		cryptfs.Warn.Printf("ino%d fh%d: Truncate: Fstat failed: %v", f.ino, f.intFd(), err) +		toggledlog.Warn.Printf("ino%d fh%d: Truncate: Fstat failed: %v", f.ino, f.intFd(), err)  		return fuse.ToStatus(err)  	} -	oldSize := f.cfs.CipherSizeToPlainSize(uint64(fi.Size())) +	oldSize := f.contentEnc.CipherSizeToPlainSize(uint64(fi.Size()))  	{ -		oldB := float32(oldSize) / float32(f.cfs.PlainBS()) -		newB := float32(newSize) / float32(f.cfs.PlainBS()) -		cryptfs.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()) +		toggledlog.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 @@ -382,7 +384,7 @@ func (f *file) Truncate(newSize uint64) fuse.Status {  			}  		} -		blocks := f.cfs.ExplodePlainRange(oldSize, newSize-oldSize) +		blocks := f.contentEnc.ExplodePlainRange(oldSize, newSize-oldSize)  		for _, b := range blocks {  			// First and last block may be partial  			if b.IsPartial() { @@ -396,7 +398,7 @@ func (f *file) Truncate(newSize uint64) fuse.Status {  				off, length := b.CiphertextRange()  				err := syscall.Ftruncate(int(f.fd.Fd()), int64(off+length))  				if err != nil { -					cryptfs.Warn.Printf("grow Ftruncate returned error: %v", err) +					toggledlog.Warn.Printf("grow Ftruncate returned error: %v", err)  					return fuse.ToStatus(err)  				}  			} @@ -404,23 +406,23 @@ func (f *file) Truncate(newSize uint64) fuse.Status {  		return fuse.OK  	} else {  		// File shrinks -		blockNo := f.cfs.PlainOffToBlockNo(newSize) -		cipherOff := f.cfs.BlockNoToCipherOff(blockNo) -		plainOff := f.cfs.BlockNoToPlainOff(blockNo) +		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 { -				cryptfs.Warn.Printf("shrink doRead returned error: %v", err) +				toggledlog.Warn.Printf("shrink doRead returned error: %v", err)  				return status  			}  		}  		// Truncate down to last complete block  		err = syscall.Ftruncate(int(f.fd.Fd()), int64(cipherOff))  		if err != nil { -			cryptfs.Warn.Printf("shrink Ftruncate returned error: %v", err) +			toggledlog.Warn.Printf("shrink Ftruncate returned error: %v", err)  			return fuse.ToStatus(err)  		}  		// Append partial block @@ -450,14 +452,14 @@ func (f *file) GetAttr(a *fuse.Attr) fuse.Status {  	f.fdLock.RLock()  	defer f.fdLock.RUnlock() -	cryptfs.Debug.Printf("file.GetAttr()") +	toggledlog.Debug.Printf("file.GetAttr()")  	st := syscall.Stat_t{}  	err := syscall.Fstat(int(f.fd.Fd()), &st)  	if err != nil {  		return fuse.ToStatus(err)  	}  	a.FromStat(&st) -	a.Size = f.cfs.CipherSizeToPlainSize(a.Size) +	a.Size = f.contentEnc.CipherSizeToPlainSize(a.Size)  	return fuse.OK  } @@ -468,7 +470,7 @@ var allocateWarned bool  func (f *file) Allocate(off uint64, sz uint64, mode uint32) fuse.Status {  	// Only warn once  	if !allocateWarned { -		cryptfs.Warn.Printf("fallocate(2) is not supported, returning ENOSYS - see https://github.com/rfjakob/gocryptfs/issues/1") +		toggledlog.Warn.Printf("fallocate(2) is not supported, returning ENOSYS - see https://github.com/rfjakob/gocryptfs/issues/1")  		allocateWarned = true  	}  	return fuse.ENOSYS diff --git a/pathfs_frontend/file_holes.go b/pathfs_frontend/file_holes.go index fd2e2c1..a147deb 100644 --- a/pathfs_frontend/file_holes.go +++ b/pathfs_frontend/file_holes.go @@ -4,13 +4,14 @@ package pathfs_frontend  import (  	"github.com/hanwen/go-fuse/fuse" -	"github.com/rfjakob/gocryptfs/cryptfs" + +	"github.com/rfjakob/gocryptfs/internal/toggledlog"  )  // Will a write to offset "off" create a file hole?  func (f *file) createsHole(plainSize uint64, off int64) bool { -	nextBlock := f.cfs.PlainOffToBlockNo(plainSize) -	targetBlock := f.cfs.PlainOffToBlockNo(uint64(off)) +	nextBlock := f.contentEnc.PlainOffToBlockNo(plainSize) +	targetBlock := f.contentEnc.PlainOffToBlockNo(uint64(off))  	if targetBlock > nextBlock {  		return true  	} @@ -19,10 +20,10 @@ func (f *file) createsHole(plainSize uint64, off int64) bool {  // Zero-pad the file of size plainSize to the next block boundary  func (f *file) zeroPad(plainSize uint64) fuse.Status { -	lastBlockLen := plainSize % f.cfs.PlainBS() -	missing := f.cfs.PlainBS() - lastBlockLen +	lastBlockLen := plainSize % f.contentEnc.PlainBS() +	missing := f.contentEnc.PlainBS() - lastBlockLen  	pad := make([]byte, missing) -	cryptfs.Debug.Printf("zeroPad: Writing %d bytes\n", missing) +	toggledlog.Debug.Printf("zeroPad: Writing %d bytes\n", missing)  	_, status := f.doWrite(pad, int64(plainSize))  	return status  } diff --git a/pathfs_frontend/fs.go b/pathfs_frontend/fs.go index a00985d..212f0a7 100644 --- a/pathfs_frontend/fs.go +++ b/pathfs_frontend/fs.go @@ -13,25 +13,41 @@ import (  	"github.com/hanwen/go-fuse/fuse"  	"github.com/hanwen/go-fuse/fuse/nodefs"  	"github.com/hanwen/go-fuse/fuse/pathfs" -	"github.com/rfjakob/gocryptfs/cryptfs" + +	"github.com/rfjakob/gocryptfs/internal/toggledlog" +	"github.com/rfjakob/gocryptfs/internal/cryptocore" +	"github.com/rfjakob/gocryptfs/internal/nametransform" +	"github.com/rfjakob/gocryptfs/internal/contentenc" +	"github.com/rfjakob/gocryptfs/internal/configfile"  ) +const plainBS = 4096 +  type FS struct { -	*cryptfs.CryptFS  	pathfs.FileSystem      // loopbackFileSystem, see go-fuse/fuse/pathfs/loopback.go  	args              Args // Stores configuration arguments  	// dirIVLock: Lock()ed if any "gocryptfs.diriv" file is modified  	// Readers must RLock() it to prevent them from seeing intermediate  	// states  	dirIVLock sync.RWMutex +	// Filename encryption helper +	nameTransform *nametransform.NameTransform +	// Content encryption helper +	contentEnc *contentenc.ContentEnc  }  // Encrypted FUSE overlay filesystem  func NewFS(args Args) *FS { + +	cryptoCore := cryptocore.New(args.Masterkey, args.OpenSSL, args.GCMIV128) +	contentEnc := contentenc.New(cryptoCore, plainBS) +	nameTransform := nametransform.New(cryptoCore, args.EMENames) +  	return &FS{ -		CryptFS:    cryptfs.NewCryptFS(args.Masterkey, args.OpenSSL, args.PlaintextNames, args.GCMIV128),  		FileSystem: pathfs.NewLoopbackFileSystem(args.Cipherdir),  		args:       args, +		nameTransform: nameTransform, +		contentEnc: contentEnc,  	}  } @@ -43,12 +59,12 @@ func (fs *FS) getBackingPath(relPath string) (string, error) {  		return "", err  	}  	cAbsPath := filepath.Join(fs.args.Cipherdir, cPath) -	cryptfs.Debug.Printf("getBackingPath: %s + %s -> %s", fs.args.Cipherdir, relPath, cAbsPath) +	toggledlog.Debug.Printf("getBackingPath: %s + %s -> %s", fs.args.Cipherdir, relPath, cAbsPath)  	return cAbsPath, nil  }  func (fs *FS) GetAttr(name string, context *fuse.Context) (*fuse.Attr, fuse.Status) { -	cryptfs.Debug.Printf("FS.GetAttr('%s')", name) +	toggledlog.Debug.Printf("FS.GetAttr('%s')", name)  	if fs.isFiltered(name) {  		return nil, fuse.EPERM  	} @@ -58,11 +74,11 @@ func (fs *FS) GetAttr(name string, context *fuse.Context) (*fuse.Attr, fuse.Stat  	}  	a, status := fs.FileSystem.GetAttr(cName, context)  	if a == nil { -		cryptfs.Debug.Printf("FS.GetAttr failed: %s", status.String()) +		toggledlog.Debug.Printf("FS.GetAttr failed: %s", status.String())  		return a, status  	}  	if a.IsRegular() { -		a.Size = fs.CipherSizeToPlainSize(a.Size) +		a.Size = fs.contentEnc.CipherSizeToPlainSize(a.Size)  	} else if a.IsSymlink() {  		target, _ := fs.Readlink(name, context)  		a.Size = uint64(len(target)) @@ -71,7 +87,7 @@ func (fs *FS) GetAttr(name string, context *fuse.Context) (*fuse.Attr, fuse.Stat  }  func (fs *FS) OpenDir(dirName string, context *fuse.Context) ([]fuse.DirEntry, fuse.Status) { -	cryptfs.Debug.Printf("OpenDir(%s)", dirName) +	toggledlog.Debug.Printf("OpenDir(%s)", dirName)  	cDirName, err := fs.encryptPath(dirName)  	if err != nil {  		return nil, fuse.ToStatus(err) @@ -81,12 +97,12 @@ func (fs *FS) OpenDir(dirName string, context *fuse.Context) ([]fuse.DirEntry, f  	if cipherEntries == nil {  		return nil, status  	} -	// Get DirIV (stays zero if DirIV if off) -	cachedIV := make([]byte, cryptfs.DIRIV_LEN) +	// Get DirIV (stays nil if DirIV if off) +	var cachedIV []byte  	if fs.args.DirIV {  		// Read the DirIV once and use it for all later name decryptions  		cDirAbsPath := filepath.Join(fs.args.Cipherdir, cDirName) -		cachedIV, err = fs.CryptFS.ReadDirIV(cDirAbsPath) +		cachedIV, err = fs.nameTransform.ReadDirIV(cDirAbsPath)  		if err != nil {  			return nil, fuse.ToStatus(err)  		} @@ -95,19 +111,19 @@ func (fs *FS) OpenDir(dirName string, context *fuse.Context) ([]fuse.DirEntry, f  	var plain []fuse.DirEntry  	for i := range cipherEntries {  		cName := cipherEntries[i].Name -		if dirName == "" && cName == cryptfs.ConfDefaultName { +		if dirName == "" && cName == configfile.ConfDefaultName {  			// silently ignore "gocryptfs.conf" in the top level dir  			continue  		} -		if fs.args.DirIV && cName == cryptfs.DIRIV_FILENAME { +		if fs.args.DirIV && cName == nametransform.DirIVFilename {  			// silently ignore "gocryptfs.diriv" everywhere if dirIV is enabled  			continue  		}  		var name string = cName  		if !fs.args.PlaintextNames { -			name, err = fs.CryptFS.DecryptName(cName, cachedIV, fs.args.EMENames) +			name, err = fs.nameTransform.DecryptName(cName, cachedIV)  			if err != nil { -				cryptfs.Warn.Printf("Invalid name \"%s\" in dir \"%s\": %s", cName, cDirName, err) +				toggledlog.Warn.Printf("Invalid name \"%s\" in dir \"%s\": %s", cName, cDirName, err)  				continue  			}  		} @@ -137,16 +153,16 @@ func (fs *FS) Open(path string, flags uint32, context *fuse.Context) (fuseFile n  	iflags, writeOnly := fs.mangleOpenFlags(flags)  	cPath, err := fs.getBackingPath(path)  	if err != nil { -		cryptfs.Debug.Printf("Open: getBackingPath: %v", err) +		toggledlog.Debug.Printf("Open: getBackingPath: %v", err)  		return nil, fuse.ToStatus(err)  	} -	cryptfs.Debug.Printf("Open: %s", cPath) +	toggledlog.Debug.Printf("Open: %s", cPath)  	f, err := os.OpenFile(cPath, iflags, 0666)  	if err != nil {  		return nil, fuse.ToStatus(err)  	} -	return NewFile(f, writeOnly, fs.CryptFS), fuse.OK +	return NewFile(f, writeOnly, fs.contentEnc), fuse.OK  }  func (fs *FS) Create(path string, flags uint32, mode uint32, context *fuse.Context) (fuseFile nodefs.File, code fuse.Status) { @@ -162,7 +178,7 @@ func (fs *FS) Create(path string, flags uint32, mode uint32, context *fuse.Conte  	if err != nil {  		return nil, fuse.ToStatus(err)  	} -	return NewFile(f, writeOnly, fs.CryptFS), fuse.OK +	return NewFile(f, writeOnly, fs.contentEnc), fuse.OK  }  func (fs *FS) Chmod(path string, mode uint32, context *fuse.Context) (code fuse.Status) { @@ -203,7 +219,7 @@ var truncateWarned bool  func (fs *FS) Truncate(path string, offset uint64, context *fuse.Context) (code fuse.Status) {  	// Only warn once  	if !truncateWarned { -		cryptfs.Warn.Printf("truncate(2) is not supported, returning ENOSYS - use ftruncate(2)") +		toggledlog.Warn.Printf("truncate(2) is not supported, returning ENOSYS - use ftruncate(2)")  		truncateWarned = true  	}  	return fuse.ENOSYS @@ -233,7 +249,7 @@ func (fs *FS) Readlink(path string, context *fuse.Context) (out string, status f  	if !fs.args.DirIV {  		target, err := fs.decryptPath(cTarget)  		if err != nil { -			cryptfs.Warn.Printf("Readlink: CBC decryption failed: %v", err) +			toggledlog.Warn.Printf("Readlink: CBC decryption failed: %v", err)  			return "", fuse.EIO  		}  		return target, fuse.OK @@ -241,12 +257,12 @@ func (fs *FS) Readlink(path string, context *fuse.Context) (out string, status f  	// Since gocryptfs v0.5 symlinks are encrypted like file contents (GCM)  	cBinTarget, err := base64.URLEncoding.DecodeString(cTarget)  	if err != nil { -		cryptfs.Warn.Printf("Readlink: %v", err) +		toggledlog.Warn.Printf("Readlink: %v", err)  		return "", fuse.EIO  	} -	target, err := fs.CryptFS.DecryptBlock([]byte(cBinTarget), 0, nil) +	target, err := fs.contentEnc.DecryptBlock([]byte(cBinTarget), 0, nil)  	if err != nil { -		cryptfs.Warn.Printf("Readlink: %v", err) +		toggledlog.Warn.Printf("Readlink: %v", err)  		return "", fuse.EIO  	}  	return string(target), fuse.OK @@ -264,7 +280,7 @@ func (fs *FS) Unlink(path string, context *fuse.Context) (code fuse.Status) {  }  func (fs *FS) Symlink(target string, linkName string, context *fuse.Context) (code fuse.Status) { -	cryptfs.Debug.Printf("Symlink(\"%s\", \"%s\")", target, linkName) +	toggledlog.Debug.Printf("Symlink(\"%s\", \"%s\")", target, linkName)  	if fs.isFiltered(linkName) {  		return fuse.EPERM  	} @@ -276,18 +292,18 @@ func (fs *FS) Symlink(target string, linkName string, context *fuse.Context) (co  	if !fs.args.DirIV {  		cTarget, err := fs.encryptPath(target)  		if err != nil { -			cryptfs.Warn.Printf("Symlink: BUG: we should not get an error here: %v", err) +			toggledlog.Warn.Printf("Symlink: BUG: we should not get an error here: %v", err)  			return fuse.ToStatus(err)  		}  		err = os.Symlink(cTarget, cPath)  		return fuse.ToStatus(err)  	}  	// Since gocryptfs v0.5 symlinks are encrypted like file contents (GCM) -	cBinTarget := fs.CryptFS.EncryptBlock([]byte(target), 0, nil) +	cBinTarget := fs.contentEnc.EncryptBlock([]byte(target), 0, nil)  	cTarget := base64.URLEncoding.EncodeToString(cBinTarget)  	err = os.Symlink(cTarget, cPath) -	cryptfs.Debug.Printf("Symlink: os.Symlink(%s, %s) = %v", cTarget, cPath, err) +	toggledlog.Debug.Printf("Symlink: os.Symlink(%s, %s) = %v", cTarget, cPath, err)  	return fuse.ToStatus(err)  } @@ -305,7 +321,7 @@ func (fs *FS) Rename(oldPath string, newPath string, context *fuse.Context) (cod  	}  	// The Rename may cause a directory to take the place of another directory.  	// That directory may still be in the DirIV cache, clear it. -	fs.CryptFS.DirIVCache.Clear() +	fs.nameTransform.DirIVCache.Clear()  	err = os.Rename(cOldPath, cNewPath) @@ -313,7 +329,7 @@ func (fs *FS) Rename(oldPath string, newPath string, context *fuse.Context) (cod  		// If an empty directory is overwritten we will always get  		// ENOTEMPTY as the "empty" directory will still contain gocryptfs.diriv.  		// Handle that case by removing the target directory and trying again. -		cryptfs.Debug.Printf("Rename: Handling ENOTEMPTY") +		toggledlog.Debug.Printf("Rename: Handling ENOTEMPTY")  		if fs.Rmdir(newPath, context) == fuse.OK {  			err = os.Rename(cOldPath, cNewPath)  		} diff --git a/pathfs_frontend/fs_dir.go b/pathfs_frontend/fs_dir.go index b1edd73..d378d28 100644 --- a/pathfs_frontend/fs_dir.go +++ b/pathfs_frontend/fs_dir.go @@ -9,7 +9,10 @@ import (  	"syscall"  	"github.com/hanwen/go-fuse/fuse" -	"github.com/rfjakob/gocryptfs/cryptfs" + +	"github.com/rfjakob/gocryptfs/internal/toggledlog" +	"github.com/rfjakob/gocryptfs/internal/cryptocore" +	"github.com/rfjakob/gocryptfs/internal/nametransform"  )  func (fs *FS) Mkdir(relPath string, mode uint32, context *fuse.Context) (code fuse.Status) { @@ -29,7 +32,7 @@ func (fs *FS) Mkdir(relPath string, mode uint32, context *fuse.Context) (code fu  	mode = mode | 0300  	// The new directory may take the place of an older one that is still in the cache -	fs.CryptFS.DirIVCache.Clear() +	fs.nameTransform.DirIVCache.Clear()  	// Create directory  	fs.dirIVLock.Lock()  	defer fs.dirIVLock.Unlock() @@ -38,13 +41,13 @@ func (fs *FS) Mkdir(relPath string, mode uint32, context *fuse.Context) (code fu  		return fuse.ToStatus(err)  	}  	// Create gocryptfs.diriv inside -	err = cryptfs.WriteDirIV(encPath) +	err = nametransform.WriteDirIV(encPath)  	if err != nil {  		// This should not happen -		cryptfs.Warn.Printf("Mkdir: WriteDirIV failed: %v", err) +		toggledlog.Warn.Printf("Mkdir: WriteDirIV failed: %v", err)  		err2 := syscall.Rmdir(encPath)  		if err2 != nil { -			cryptfs.Warn.Printf("Mkdir: Rmdir rollback failed: %v", err2) +			toggledlog.Warn.Printf("Mkdir: Rmdir rollback failed: %v", err2)  		}  		return fuse.ToStatus(err)  	} @@ -53,7 +56,7 @@ func (fs *FS) Mkdir(relPath string, mode uint32, context *fuse.Context) (code fu  	if origMode != mode {  		err = os.Chmod(encPath, os.FileMode(origMode))  		if err != nil { -			cryptfs.Warn.Printf("Mkdir: Chmod failed: %v", err) +			toggledlog.Warn.Printf("Mkdir: Chmod failed: %v", err)  		}  	} @@ -74,17 +77,17 @@ func (fs *FS) Rmdir(name string, context *fuse.Context) (code fuse.Status) {  	fd, err := os.Open(encPath)  	if perr, ok := err.(*os.PathError); ok && perr.Err == syscall.EACCES {  		// We need permission to read and modify the directory -		cryptfs.Debug.Printf("Rmdir: handling EACCESS") +		toggledlog.Debug.Printf("Rmdir: handling EACCESS")  		fi, err2 := os.Stat(encPath)  		if err2 != nil { -			cryptfs.Debug.Printf("Rmdir: Stat: %v", err2) +			toggledlog.Debug.Printf("Rmdir: Stat: %v", err2)  			return fuse.ToStatus(err2)  		}  		origMode := fi.Mode()  		newMode := origMode | 0700  		err2 = os.Chmod(encPath, newMode)  		if err2 != nil { -			cryptfs.Debug.Printf("Rmdir: Chmod failed: %v", err2) +			toggledlog.Debug.Printf("Rmdir: Chmod failed: %v", err2)  			return fuse.ToStatus(err)  		}  		defer func() { @@ -92,7 +95,7 @@ func (fs *FS) Rmdir(name string, context *fuse.Context) (code fuse.Status) {  				// Undo the chmod if removing the directory failed  				err3 := os.Chmod(encPath, origMode)  				if err3 != nil { -					cryptfs.Warn.Printf("Rmdir: Chmod rollback failed: %v", err2) +					toggledlog.Warn.Printf("Rmdir: Chmod rollback failed: %v", err2)  				}  			}  		}() @@ -100,35 +103,36 @@ func (fs *FS) Rmdir(name string, context *fuse.Context) (code fuse.Status) {  		fd, err = os.Open(encPath)  	}  	if err != nil { -		cryptfs.Debug.Printf("Rmdir: Open: %v", err) +		toggledlog.Debug.Printf("Rmdir: Open: %v", err)  		return fuse.ToStatus(err)  	}  	list, err := fd.Readdirnames(10)  	fd.Close()  	if err != nil { -		cryptfs.Debug.Printf("Rmdir: Readdirnames: %v", err) +		toggledlog.Debug.Printf("Rmdir: Readdirnames: %v", err)  		return fuse.ToStatus(err)  	}  	if len(list) > 1 {  		return fuse.ToStatus(syscall.ENOTEMPTY)  	} else if len(list) == 0 { -		cryptfs.Warn.Printf("Rmdir: gocryptfs.diriv missing, allowing deletion") +		toggledlog.Warn.Printf("Rmdir: gocryptfs.diriv missing, allowing deletion")  		return fuse.ToStatus(syscall.Rmdir(encPath))  	}  	// Move "gocryptfs.diriv" to the parent dir as "gocryptfs.diriv.rmdir.XYZ" -	dirivPath := filepath.Join(encPath, cryptfs.DIRIV_FILENAME) +	dirivPath := filepath.Join(encPath, nametransform.DirIVFilename)  	parentDir := filepath.Dir(encPath) -	tmpName := fmt.Sprintf("gocryptfs.diriv.rmdir.%d", cryptfs.RandUint64()) +	tmpName := fmt.Sprintf("gocryptfs.diriv.rmdir.%d", cryptocore.RandUint64())  	tmpDirivPath := filepath.Join(parentDir, tmpName) -	cryptfs.Debug.Printf("Rmdir: Renaming %s to %s", cryptfs.DIRIV_FILENAME, tmpDirivPath) +	toggledlog.Debug.Printf("Rmdir: Renaming %s to %s", nametransform.DirIVFilename, tmpDirivPath)  	// The directory is in an inconsistent state between rename and rmdir. Protect against  	// concurrent readers.  	fs.dirIVLock.Lock()  	defer fs.dirIVLock.Unlock()  	err = os.Rename(dirivPath, tmpDirivPath)  	if err != nil { -		cryptfs.Warn.Printf("Rmdir: Renaming %s to %s failed: %v", cryptfs.DIRIV_FILENAME, tmpDirivPath, err) +		toggledlog.Warn.Printf("Rmdir: Renaming %s to %s failed: %v", +			nametransform.DirIVFilename, tmpDirivPath, err)  		return fuse.ToStatus(err)  	}  	// Actual Rmdir @@ -138,16 +142,16 @@ func (fs *FS) Rmdir(name string, context *fuse.Context) (code fuse.Status) {  		// meantime, undo the rename  		err2 := os.Rename(tmpDirivPath, dirivPath)  		if err2 != nil { -			cryptfs.Warn.Printf("Rmdir: Rename rollback failed: %v", err2) +			toggledlog.Warn.Printf("Rmdir: Rename rollback failed: %v", err2)  		}  		return fuse.ToStatus(err)  	}  	// Delete "gocryptfs.diriv.rmdir.INODENUMBER"  	err = syscall.Unlink(tmpDirivPath)  	if err != nil { -		cryptfs.Warn.Printf("Rmdir: Could not clean up %s: %v", tmpName, err) +		toggledlog.Warn.Printf("Rmdir: Could not clean up %s: %v", tmpName, err)  	}  	// The now-deleted directory may have been in the DirIV cache. Clear it. -	fs.CryptFS.DirIVCache.Clear() +	fs.nameTransform.DirIVCache.Clear()  	return fuse.OK  } diff --git a/pathfs_frontend/names.go b/pathfs_frontend/names.go index bd7a249..160fa0a 100644 --- a/pathfs_frontend/names.go +++ b/pathfs_frontend/names.go @@ -3,7 +3,8 @@ package pathfs_frontend  // This file forwards file encryption operations to cryptfs  import ( -	"github.com/rfjakob/gocryptfs/cryptfs" +	"github.com/rfjakob/gocryptfs/internal/configfile" +	mylog "github.com/rfjakob/gocryptfs/internal/toggledlog"  )  // isFiltered - check if plaintext "path" should be forbidden @@ -14,9 +15,9 @@ func (fs *FS) isFiltered(path string) bool {  		return false  	}  	// gocryptfs.conf in the root directory is forbidden -	if path == cryptfs.ConfDefaultName { -		cryptfs.Info.Printf("The name /%s is reserved when -plaintextnames is used\n", -			cryptfs.ConfDefaultName) +	if path == configfile.ConfDefaultName { +		mylog.Info.Printf("The name /%s is reserved when -plaintextnames is used\n", +			configfile.ConfDefaultName)  		return true  	}  	// Note: gocryptfs.diriv is NOT forbidden because diriv and plaintextnames @@ -30,11 +31,11 @@ func (fs *FS) encryptPath(plainPath string) (string, error) {  		return plainPath, nil  	}  	if !fs.args.DirIV { -		return fs.CryptFS.EncryptPathNoIV(plainPath), nil +		return fs.nameTransform.EncryptPathNoIV(plainPath), nil  	}  	fs.dirIVLock.RLock()  	defer fs.dirIVLock.RUnlock() -	return fs.CryptFS.EncryptPathDirIV(plainPath, fs.args.Cipherdir, fs.args.EMENames) +	return fs.nameTransform.EncryptPathDirIV(plainPath, fs.args.Cipherdir)  }  // decryptPath - decrypt relative ciphertext path @@ -43,9 +44,9 @@ func (fs *FS) decryptPath(cipherPath string) (string, error) {  		return cipherPath, nil  	}  	if !fs.args.DirIV { -		return fs.CryptFS.DecryptPathNoIV(cipherPath) +		return fs.nameTransform.DecryptPathNoIV(cipherPath)  	}  	fs.dirIVLock.RLock()  	defer fs.dirIVLock.RUnlock() -	return fs.CryptFS.DecryptPathDirIV(cipherPath, fs.args.Cipherdir, fs.args.EMENames) +	return fs.nameTransform.DecryptPathDirIV(cipherPath, fs.args.Cipherdir, fs.args.EMENames)  } | 
