fusefrontend: export "File" type
"gocryptfs -fsck" will need access to helper functions, and to get that, it will need to cast a gofuse.File to a fusefrontend.File. Make fusefrontend.File exported to make this work.
This commit is contained in:
parent
4a73637782
commit
a2af1fb5da
|
@ -23,10 +23,10 @@ import (
|
||||||
"github.com/rfjakob/gocryptfs/internal/tlog"
|
"github.com/rfjakob/gocryptfs/internal/tlog"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ nodefs.File = &file{} // Verify that interface is implemented.
|
var _ nodefs.File = &File{} // Verify that interface is implemented.
|
||||||
|
|
||||||
// File - based on loopbackFile in go-fuse/fuse/nodefs/files.go
|
// File - based on loopbackFile in go-fuse/fuse/nodefs/files.go
|
||||||
type file struct {
|
type File struct {
|
||||||
fd *os.File
|
fd *os.File
|
||||||
// Has Release() already been called on this file? This also means that the
|
// Has Release() already been called on this file? This also means that the
|
||||||
// wlock entry has been freed, so let's not crash trying to access it.
|
// wlock entry has been freed, so let's not crash trying to access it.
|
||||||
|
@ -60,7 +60,7 @@ type file struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewFile returns a new go-fuse File instance.
|
// NewFile returns a new go-fuse File instance.
|
||||||
func NewFile(fd *os.File, fs *FS) (nodefs.File, fuse.Status) {
|
func NewFile(fd *os.File, fs *FS) (*File, fuse.Status) {
|
||||||
var st syscall.Stat_t
|
var st syscall.Stat_t
|
||||||
err := syscall.Fstat(int(fd.Fd()), &st)
|
err := syscall.Fstat(int(fd.Fd()), &st)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -70,7 +70,7 @@ func NewFile(fd *os.File, fs *FS) (nodefs.File, fuse.Status) {
|
||||||
qi := openfiletable.QInoFromStat(&st)
|
qi := openfiletable.QInoFromStat(&st)
|
||||||
e := openfiletable.Register(qi)
|
e := openfiletable.Register(qi)
|
||||||
|
|
||||||
return &file{
|
return &File{
|
||||||
fd: fd,
|
fd: fd,
|
||||||
contentEnc: fs.contentEnc,
|
contentEnc: fs.contentEnc,
|
||||||
qIno: qi,
|
qIno: qi,
|
||||||
|
@ -83,13 +83,13 @@ func NewFile(fd *os.File, fs *FS) (nodefs.File, fuse.Status) {
|
||||||
|
|
||||||
// intFd - return the backing file descriptor as an integer. Used for debug
|
// intFd - return the backing file descriptor as an integer. Used for debug
|
||||||
// messages.
|
// messages.
|
||||||
func (f *file) intFd() int {
|
func (f *File) intFd() int {
|
||||||
return int(f.fd.Fd())
|
return int(f.fd.Fd())
|
||||||
}
|
}
|
||||||
|
|
||||||
// readFileID loads the file header from disk and extracts the file ID.
|
// readFileID loads the file header from disk and extracts the file ID.
|
||||||
// Returns io.EOF if the file is empty.
|
// Returns io.EOF if the file is empty.
|
||||||
func (f *file) readFileID() ([]byte, error) {
|
func (f *File) readFileID() ([]byte, error) {
|
||||||
// We read +1 byte to determine if the file has actual content
|
// We read +1 byte to determine if the file has actual content
|
||||||
// and not only the header. A header-only file will be considered empty.
|
// and not only the header. A header-only file will be considered empty.
|
||||||
// This makes File ID poisoning more difficult.
|
// This makes File ID poisoning more difficult.
|
||||||
|
@ -115,7 +115,7 @@ func (f *file) readFileID() ([]byte, error) {
|
||||||
// createHeader creates a new random header and writes it to disk.
|
// createHeader creates a new random header and writes it to disk.
|
||||||
// Returns the new file ID.
|
// Returns the new file ID.
|
||||||
// The caller must hold fileIDLock.Lock().
|
// The caller must hold fileIDLock.Lock().
|
||||||
func (f *file) createHeader() (fileID []byte, err error) {
|
func (f *File) createHeader() (fileID []byte, err error) {
|
||||||
h := contentenc.RandomHeader()
|
h := contentenc.RandomHeader()
|
||||||
buf := h.Pack()
|
buf := h.Pack()
|
||||||
// Prevent partially written (=corrupt) header by preallocating the space beforehand
|
// Prevent partially written (=corrupt) header by preallocating the space beforehand
|
||||||
|
@ -143,7 +143,7 @@ func (f *file) createHeader() (fileID []byte, err error) {
|
||||||
//
|
//
|
||||||
// Called by Read() for normal reading,
|
// Called by Read() for normal reading,
|
||||||
// by Write() and Truncate() for Read-Modify-Write
|
// by Write() and Truncate() for Read-Modify-Write
|
||||||
func (f *file) doRead(dst []byte, off uint64, length uint64) ([]byte, fuse.Status) {
|
func (f *File) doRead(dst []byte, off uint64, length uint64) ([]byte, fuse.Status) {
|
||||||
// Make sure we have the file ID.
|
// Make sure we have the file ID.
|
||||||
f.fileTableEntry.HeaderLock.RLock()
|
f.fileTableEntry.HeaderLock.RLock()
|
||||||
if f.fileTableEntry.ID == nil {
|
if f.fileTableEntry.ID == nil {
|
||||||
|
@ -230,7 +230,7 @@ func (f *file) doRead(dst []byte, off uint64, length uint64) ([]byte, fuse.Statu
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read - FUSE call
|
// Read - FUSE call
|
||||||
func (f *file) Read(buf []byte, off int64) (resultData fuse.ReadResult, code fuse.Status) {
|
func (f *File) Read(buf []byte, off int64) (resultData fuse.ReadResult, code fuse.Status) {
|
||||||
if len(buf) > fuse.MAX_KERNEL_WRITE {
|
if len(buf) > fuse.MAX_KERNEL_WRITE {
|
||||||
// This would crash us due to our fixed-size buffer pool
|
// This would crash us due to our fixed-size buffer pool
|
||||||
tlog.Warn.Printf("Read: rejecting oversized request with EMSGSIZE, len=%d", len(buf))
|
tlog.Warn.Printf("Read: rejecting oversized request with EMSGSIZE, len=%d", len(buf))
|
||||||
|
@ -263,7 +263,7 @@ func (f *file) Read(buf []byte, off int64) (resultData fuse.ReadResult, code fus
|
||||||
// and by Truncate() to rewrite the last file block.
|
// and by Truncate() to rewrite the last file block.
|
||||||
//
|
//
|
||||||
// Empty writes do nothing and are allowed.
|
// Empty writes do nothing and are allowed.
|
||||||
func (f *file) doWrite(data []byte, off int64) (uint32, fuse.Status) {
|
func (f *File) doWrite(data []byte, off int64) (uint32, fuse.Status) {
|
||||||
// Read header from disk, create a new one if the file is empty
|
// Read header from disk, create a new one if the file is empty
|
||||||
f.fileTableEntry.HeaderLock.RLock()
|
f.fileTableEntry.HeaderLock.RLock()
|
||||||
if f.fileTableEntry.ID == nil {
|
if f.fileTableEntry.ID == nil {
|
||||||
|
@ -337,7 +337,7 @@ func (f *file) doWrite(data []byte, off int64) (uint32, fuse.Status) {
|
||||||
// This is an optimisation for streaming writes on NFS where a
|
// This is an optimisation for streaming writes on NFS where a
|
||||||
// Stat() call is very expensive.
|
// Stat() call is very expensive.
|
||||||
// The caller must "wlock.lock(f.devIno.ino)" otherwise this check would be racy.
|
// The caller must "wlock.lock(f.devIno.ino)" otherwise this check would be racy.
|
||||||
func (f *file) isConsecutiveWrite(off int64) bool {
|
func (f *File) isConsecutiveWrite(off int64) bool {
|
||||||
opCount := openfiletable.WriteOpCount()
|
opCount := openfiletable.WriteOpCount()
|
||||||
return opCount == f.lastOpCount+1 && off == f.lastWrittenOffset+1
|
return opCount == f.lastOpCount+1 && off == f.lastWrittenOffset+1
|
||||||
}
|
}
|
||||||
|
@ -345,7 +345,7 @@ func (f *file) isConsecutiveWrite(off int64) bool {
|
||||||
// Write - FUSE call
|
// Write - FUSE call
|
||||||
//
|
//
|
||||||
// If the write creates a hole, pads the file to the next block boundary.
|
// If the write creates a hole, pads the file to the next block boundary.
|
||||||
func (f *file) Write(data []byte, off int64) (uint32, fuse.Status) {
|
func (f *File) Write(data []byte, off int64) (uint32, fuse.Status) {
|
||||||
if len(data) > fuse.MAX_KERNEL_WRITE {
|
if len(data) > fuse.MAX_KERNEL_WRITE {
|
||||||
// This would crash us due to our fixed-size buffer pool
|
// This would crash us due to our fixed-size buffer pool
|
||||||
tlog.Warn.Printf("Write: rejecting oversized request with EMSGSIZE, len=%d", len(data))
|
tlog.Warn.Printf("Write: rejecting oversized request with EMSGSIZE, len=%d", len(data))
|
||||||
|
@ -381,7 +381,7 @@ func (f *file) Write(data []byte, off int64) (uint32, fuse.Status) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Release - FUSE call, close file
|
// Release - FUSE call, close file
|
||||||
func (f *file) Release() {
|
func (f *File) Release() {
|
||||||
f.fdLock.Lock()
|
f.fdLock.Lock()
|
||||||
if f.released {
|
if f.released {
|
||||||
log.Panicf("ino%d fh%d: double release", f.qIno.Ino, f.intFd())
|
log.Panicf("ino%d fh%d: double release", f.qIno.Ino, f.intFd())
|
||||||
|
@ -394,7 +394,7 @@ func (f *file) Release() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flush - FUSE call
|
// Flush - FUSE call
|
||||||
func (f *file) Flush() fuse.Status {
|
func (f *File) Flush() fuse.Status {
|
||||||
f.fdLock.RLock()
|
f.fdLock.RLock()
|
||||||
defer f.fdLock.RUnlock()
|
defer f.fdLock.RUnlock()
|
||||||
|
|
||||||
|
@ -410,14 +410,14 @@ func (f *file) Flush() fuse.Status {
|
||||||
return fuse.ToStatus(err)
|
return fuse.ToStatus(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *file) Fsync(flags int) (code fuse.Status) {
|
func (f *File) Fsync(flags int) (code fuse.Status) {
|
||||||
f.fdLock.RLock()
|
f.fdLock.RLock()
|
||||||
defer f.fdLock.RUnlock()
|
defer f.fdLock.RUnlock()
|
||||||
|
|
||||||
return fuse.ToStatus(syscall.Fsync(int(f.fd.Fd())))
|
return fuse.ToStatus(syscall.Fsync(int(f.fd.Fd())))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *file) Chmod(mode uint32) fuse.Status {
|
func (f *File) Chmod(mode uint32) fuse.Status {
|
||||||
f.fdLock.RLock()
|
f.fdLock.RLock()
|
||||||
defer f.fdLock.RUnlock()
|
defer f.fdLock.RUnlock()
|
||||||
|
|
||||||
|
@ -427,14 +427,14 @@ func (f *file) Chmod(mode uint32) fuse.Status {
|
||||||
return fuse.ToStatus(err)
|
return fuse.ToStatus(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *file) Chown(uid uint32, gid uint32) fuse.Status {
|
func (f *File) Chown(uid uint32, gid uint32) fuse.Status {
|
||||||
f.fdLock.RLock()
|
f.fdLock.RLock()
|
||||||
defer f.fdLock.RUnlock()
|
defer f.fdLock.RUnlock()
|
||||||
|
|
||||||
return fuse.ToStatus(f.fd.Chown(int(uid), int(gid)))
|
return fuse.ToStatus(f.fd.Chown(int(uid), int(gid)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *file) GetAttr(a *fuse.Attr) fuse.Status {
|
func (f *File) GetAttr(a *fuse.Attr) fuse.Status {
|
||||||
f.fdLock.RLock()
|
f.fdLock.RLock()
|
||||||
defer f.fdLock.RUnlock()
|
defer f.fdLock.RUnlock()
|
||||||
|
|
||||||
|
@ -453,7 +453,7 @@ func (f *file) GetAttr(a *fuse.Attr) fuse.Status {
|
||||||
return fuse.OK
|
return fuse.OK
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *file) Utimens(a *time.Time, m *time.Time) fuse.Status {
|
func (f *File) Utimens(a *time.Time, m *time.Time) fuse.Status {
|
||||||
f.fdLock.RLock()
|
f.fdLock.RLock()
|
||||||
defer f.fdLock.RUnlock()
|
defer f.fdLock.RUnlock()
|
||||||
return f.loopbackFile.Utimens(a, m)
|
return f.loopbackFile.Utimens(a, m)
|
||||||
|
|
|
@ -36,7 +36,7 @@ var allocateWarnOnce sync.Once
|
||||||
// complicated and hard to get right.
|
// complicated and hard to get right.
|
||||||
//
|
//
|
||||||
// Other modes (hole punching, zeroing) are not supported.
|
// Other modes (hole punching, zeroing) are not supported.
|
||||||
func (f *file) Allocate(off uint64, sz uint64, mode uint32) fuse.Status {
|
func (f *File) Allocate(off uint64, sz uint64, mode uint32) fuse.Status {
|
||||||
if mode != FALLOC_DEFAULT && mode != FALLOC_FL_KEEP_SIZE {
|
if mode != FALLOC_DEFAULT && mode != FALLOC_FL_KEEP_SIZE {
|
||||||
f := func() {
|
f := func() {
|
||||||
tlog.Warn.Printf("fallocate: only mode 0 (default) and 1 (keep size) are supported")
|
tlog.Warn.Printf("fallocate: only mode 0 (default) and 1 (keep size) are supported")
|
||||||
|
@ -92,7 +92,7 @@ func (f *file) Allocate(off uint64, sz uint64, mode uint32) fuse.Status {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Truncate - FUSE call
|
// Truncate - FUSE call
|
||||||
func (f *file) Truncate(newSize uint64) fuse.Status {
|
func (f *File) Truncate(newSize uint64) fuse.Status {
|
||||||
f.fdLock.RLock()
|
f.fdLock.RLock()
|
||||||
defer f.fdLock.RUnlock()
|
defer f.fdLock.RUnlock()
|
||||||
if f.released {
|
if f.released {
|
||||||
|
@ -165,7 +165,7 @@ func (f *file) Truncate(newSize uint64) fuse.Status {
|
||||||
}
|
}
|
||||||
|
|
||||||
// statPlainSize stats the file and returns the plaintext size
|
// statPlainSize stats the file and returns the plaintext size
|
||||||
func (f *file) statPlainSize() (uint64, error) {
|
func (f *File) statPlainSize() (uint64, error) {
|
||||||
fi, err := f.fd.Stat()
|
fi, err := f.fd.Stat()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tlog.Warn.Printf("ino%d fh%d: statPlainSize: %v", f.qIno.Ino, f.intFd(), err)
|
tlog.Warn.Printf("ino%d fh%d: statPlainSize: %v", f.qIno.Ino, f.intFd(), err)
|
||||||
|
@ -179,7 +179,7 @@ func (f *file) statPlainSize() (uint64, error) {
|
||||||
// truncateGrowFile extends a file using seeking or ftruncate performing RMW on
|
// truncateGrowFile extends a file using seeking or ftruncate performing RMW on
|
||||||
// the first and last block as necessary. New blocks in the middle become
|
// the first and last block as necessary. New blocks in the middle become
|
||||||
// file holes unless they have been fallocate()'d beforehand.
|
// file holes unless they have been fallocate()'d beforehand.
|
||||||
func (f *file) truncateGrowFile(oldPlainSz uint64, newPlainSz uint64) fuse.Status {
|
func (f *File) truncateGrowFile(oldPlainSz uint64, newPlainSz uint64) fuse.Status {
|
||||||
if newPlainSz <= oldPlainSz {
|
if newPlainSz <= oldPlainSz {
|
||||||
log.Panicf("BUG: newSize=%d <= oldSize=%d", newPlainSz, oldPlainSz)
|
log.Panicf("BUG: newSize=%d <= oldSize=%d", newPlainSz, oldPlainSz)
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ import (
|
||||||
|
|
||||||
// Will a write to plaintext offset "targetOff" create a file hole in the
|
// Will a write to plaintext offset "targetOff" create a file hole in the
|
||||||
// ciphertext? If yes, zero-pad the last ciphertext block.
|
// ciphertext? If yes, zero-pad the last ciphertext block.
|
||||||
func (f *file) writePadHole(targetOff int64) fuse.Status {
|
func (f *File) writePadHole(targetOff int64) fuse.Status {
|
||||||
// Get the current file size.
|
// Get the current file size.
|
||||||
fi, err := f.fd.Stat()
|
fi, err := f.fd.Stat()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -41,7 +41,7 @@ func (f *file) writePadHole(targetOff int64) fuse.Status {
|
||||||
|
|
||||||
// Zero-pad the file of size plainSize to the next block boundary. This is a no-op
|
// Zero-pad the file of size plainSize to the next block boundary. This is a no-op
|
||||||
// if the file is already block-aligned.
|
// if the file is already block-aligned.
|
||||||
func (f *file) zeroPad(plainSize uint64) fuse.Status {
|
func (f *File) zeroPad(plainSize uint64) fuse.Status {
|
||||||
lastBlockLen := plainSize % f.contentEnc.PlainBS()
|
lastBlockLen := plainSize % f.contentEnc.PlainBS()
|
||||||
if lastBlockLen == 0 {
|
if lastBlockLen == 0 {
|
||||||
// Already block-aligned
|
// Already block-aligned
|
||||||
|
|
Loading…
Reference in New Issue