v2api/reverse: implement Read
This commit is contained in:
parent
5276092663
commit
6d4f1a6888
70
internal/fusefrontend_reverse/file.go
Normal file
70
internal/fusefrontend_reverse/file.go
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
package fusefrontend_reverse
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"os"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/hanwen/go-fuse/v2/fs"
|
||||||
|
"github.com/hanwen/go-fuse/v2/fuse"
|
||||||
|
|
||||||
|
"github.com/rfjakob/gocryptfs/internal/contentenc"
|
||||||
|
)
|
||||||
|
|
||||||
|
type File struct {
|
||||||
|
// Backing FD
|
||||||
|
fd *os.File
|
||||||
|
// File header (contains the IV)
|
||||||
|
header contentenc.FileHeader
|
||||||
|
// IV for block 0
|
||||||
|
block0IV []byte
|
||||||
|
// Content encryption helper
|
||||||
|
contentEnc *contentenc.ContentEnc
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read - FUSE call
|
||||||
|
func (f *File) Read(ctx context.Context, buf []byte, ioff int64) (resultData fuse.ReadResult, errno syscall.Errno) {
|
||||||
|
length := uint64(len(buf))
|
||||||
|
off := uint64(ioff)
|
||||||
|
out := bytes.NewBuffer(buf[:0])
|
||||||
|
var header []byte
|
||||||
|
|
||||||
|
// Synthesize file header
|
||||||
|
if off < contentenc.HeaderLen {
|
||||||
|
header = f.header.Pack()
|
||||||
|
// Truncate to requested part
|
||||||
|
end := int(off) + len(buf)
|
||||||
|
if end > len(header) {
|
||||||
|
end = len(header)
|
||||||
|
}
|
||||||
|
header = header[off:end]
|
||||||
|
// Write into output buffer and adjust offsets
|
||||||
|
out.Write(header)
|
||||||
|
hLen := uint64(len(header))
|
||||||
|
off += hLen
|
||||||
|
length -= hLen
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read actual file data
|
||||||
|
if length > 0 {
|
||||||
|
fileData, err := f.readBackingFile(off, length)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fs.ToErrno(err)
|
||||||
|
}
|
||||||
|
if len(fileData) == 0 {
|
||||||
|
// If we could not read any actual data, we also don't want to
|
||||||
|
// return the file header. An empty file stays empty in encrypted
|
||||||
|
// form.
|
||||||
|
return nil, 0
|
||||||
|
}
|
||||||
|
out.Write(fileData)
|
||||||
|
}
|
||||||
|
|
||||||
|
return fuse.ReadResultData(out.Bytes()), 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release - FUSE call, close file
|
||||||
|
func (f *File) Release(context.Context) syscall.Errno {
|
||||||
|
return fs.ToErrno(f.fd.Close())
|
||||||
|
}
|
23
internal/fusefrontend_reverse/file_api_check.go
Normal file
23
internal/fusefrontend_reverse/file_api_check.go
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package fusefrontend_reverse
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/hanwen/go-fuse/v2/fs"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Check that we have implemented the fs.File* interfaces
|
||||||
|
var _ = (fs.FileReader)((*File)(nil))
|
||||||
|
var _ = (fs.FileReleaser)((*File)(nil))
|
||||||
|
|
||||||
|
/* TODO
|
||||||
|
var _ = (fs.FileGetattrer)((*File2)(nil))
|
||||||
|
var _ = (fs.FileSetattrer)((*File2)(nil))
|
||||||
|
var _ = (fs.FileWriter)((*File2)(nil))
|
||||||
|
var _ = (fs.FileFsyncer)((*File2)(nil))
|
||||||
|
var _ = (fs.FileFlusher)((*File2)(nil))
|
||||||
|
var _ = (fs.FileAllocater)((*File2)(nil))
|
||||||
|
var _ = (fs.FileLseeker)((*File2)(nil))
|
||||||
|
var _ = (fs.FileHandle)((*File2)(nil))
|
||||||
|
var _ = (fs.FileGetlker)((*File2)(nil))
|
||||||
|
var _ = (fs.FileSetlker)((*File2)(nil))
|
||||||
|
var _ = (fs.FileSetlkwer)((*File2)(nil))
|
||||||
|
*/
|
62
internal/fusefrontend_reverse/file_helpers.go
Normal file
62
internal/fusefrontend_reverse/file_helpers.go
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
package fusefrontend_reverse
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/rfjakob/gocryptfs/internal/contentenc"
|
||||||
|
"github.com/rfjakob/gocryptfs/internal/pathiv"
|
||||||
|
"github.com/rfjakob/gocryptfs/internal/tlog"
|
||||||
|
)
|
||||||
|
|
||||||
|
var inodeTable sync.Map
|
||||||
|
|
||||||
|
// encryptBlocks - encrypt "plaintext" into a number of ciphertext blocks.
|
||||||
|
// "plaintext" must already be block-aligned.
|
||||||
|
func (rf *File) encryptBlocks(plaintext []byte, firstBlockNo uint64, fileID []byte, block0IV []byte) []byte {
|
||||||
|
inBuf := bytes.NewBuffer(plaintext)
|
||||||
|
var outBuf bytes.Buffer
|
||||||
|
bs := int(rf.contentEnc.PlainBS())
|
||||||
|
for blockNo := firstBlockNo; inBuf.Len() > 0; blockNo++ {
|
||||||
|
inBlock := inBuf.Next(bs)
|
||||||
|
iv := pathiv.BlockIV(block0IV, blockNo)
|
||||||
|
outBlock := rf.contentEnc.EncryptBlockNonce(inBlock, blockNo, fileID, iv)
|
||||||
|
outBuf.Write(outBlock)
|
||||||
|
}
|
||||||
|
return outBuf.Bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
// readBackingFile: read from the backing plaintext file, encrypt it, return the
|
||||||
|
// ciphertext.
|
||||||
|
// "off" ... ciphertext offset (must be >= HEADER_LEN)
|
||||||
|
// "length" ... ciphertext length
|
||||||
|
func (f *File) readBackingFile(off uint64, length uint64) (out []byte, err error) {
|
||||||
|
blocks := f.contentEnc.ExplodeCipherRange(off, length)
|
||||||
|
|
||||||
|
// Read the backing plaintext in one go
|
||||||
|
alignedOffset, alignedLength := contentenc.JointPlaintextRange(blocks)
|
||||||
|
plaintext := make([]byte, int(alignedLength))
|
||||||
|
n, err := f.fd.ReadAt(plaintext, int64(alignedOffset))
|
||||||
|
if err != nil && err != io.EOF {
|
||||||
|
tlog.Warn.Printf("readBackingFile: ReadAt: %s", err.Error())
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Truncate buffer down to actually read bytes
|
||||||
|
plaintext = plaintext[0:n]
|
||||||
|
|
||||||
|
// Encrypt blocks
|
||||||
|
ciphertext := f.encryptBlocks(plaintext, blocks[0].BlockNo, f.header.ID, f.block0IV)
|
||||||
|
|
||||||
|
// Crop down to the relevant part
|
||||||
|
lenHave := len(ciphertext)
|
||||||
|
skip := blocks[0].Skip
|
||||||
|
endWant := int(skip + length)
|
||||||
|
if lenHave > endWant {
|
||||||
|
out = ciphertext[skip:endWant]
|
||||||
|
} else if lenHave > int(skip) {
|
||||||
|
out = ciphertext[skip:lenHave]
|
||||||
|
} // else: out stays empty, file was smaller than the requested offset
|
||||||
|
|
||||||
|
return out, nil
|
||||||
|
}
|
@ -2,6 +2,8 @@ package fusefrontend_reverse
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
@ -10,8 +12,10 @@ import (
|
|||||||
"github.com/hanwen/go-fuse/v2/fs"
|
"github.com/hanwen/go-fuse/v2/fs"
|
||||||
"github.com/hanwen/go-fuse/v2/fuse"
|
"github.com/hanwen/go-fuse/v2/fuse"
|
||||||
|
|
||||||
"github.com/rfjakob/gocryptfs/internal/configfile"
|
"github.com/rfjakob/gocryptfs/internal/contentenc"
|
||||||
|
"github.com/rfjakob/gocryptfs/internal/pathiv"
|
||||||
"github.com/rfjakob/gocryptfs/internal/syscallcompat"
|
"github.com/rfjakob/gocryptfs/internal/syscallcompat"
|
||||||
|
"github.com/rfjakob/gocryptfs/internal/tlog"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Node is a file or directory in the filesystem tree
|
// Node is a file or directory in the filesystem tree
|
||||||
@ -33,15 +37,7 @@ func (n *Node) Lookup(ctx context.Context, cName string, out *fuse.EntryOut) (ch
|
|||||||
return n.lookupLongnameName(ctx, cName, out)
|
return n.lookupLongnameName(ctx, cName, out)
|
||||||
} else if t == typeConfig {
|
} else if t == typeConfig {
|
||||||
// gocryptfs.conf
|
// gocryptfs.conf
|
||||||
var err error
|
return n.lookupConf(ctx, out)
|
||||||
pName = configfile.ConfReverseName
|
|
||||||
rn := n.rootNode()
|
|
||||||
dirfd, err = syscallcompat.OpenDirNofollow(rn.args.Cipherdir, "")
|
|
||||||
if err != nil {
|
|
||||||
errno = fs.ToErrno(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer syscall.Close(dirfd)
|
|
||||||
} else if t == typeReal {
|
} else if t == typeReal {
|
||||||
// real file
|
// real file
|
||||||
dirfd, pName, errno = n.prepareAtSyscall(cName)
|
dirfd, pName, errno = n.prepareAtSyscall(cName)
|
||||||
@ -112,3 +108,73 @@ func (n *Node) Readlink(ctx context.Context) (out []byte, errno syscall.Errno) {
|
|||||||
cName := filepath.Base(n.Path())
|
cName := filepath.Base(n.Path())
|
||||||
return n.readlink(dirfd, cName, pName)
|
return n.readlink(dirfd, cName, pName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Open - FUSE call. Open already-existing file.
|
||||||
|
//
|
||||||
|
// Symlink-safe through Openat().
|
||||||
|
func (n *Node) Open(ctx context.Context, flags uint32) (fh fs.FileHandle, fuseFlags uint32, errno syscall.Errno) {
|
||||||
|
dirfd, pName, errno := n.prepareAtSyscall("")
|
||||||
|
if errno != 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer syscall.Close(dirfd)
|
||||||
|
|
||||||
|
fd, err := syscallcompat.Openat(dirfd, pName, syscall.O_RDONLY|syscall.O_NOFOLLOW, 0)
|
||||||
|
if err != nil {
|
||||||
|
errno = fs.ToErrno(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reject access if the file descriptor does not refer to a regular file.
|
||||||
|
var st syscall.Stat_t
|
||||||
|
err = syscall.Fstat(fd, &st)
|
||||||
|
if err != nil {
|
||||||
|
tlog.Warn.Printf("Open: Fstat error: %v", err)
|
||||||
|
syscall.Close(fd)
|
||||||
|
errno = fs.ToErrno(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var a fuse.Attr
|
||||||
|
a.FromStat(&st)
|
||||||
|
if !a.IsRegular() {
|
||||||
|
tlog.Warn.Printf("ino%d: newFile: not a regular file", st.Ino)
|
||||||
|
syscall.Close(fd)
|
||||||
|
errno = syscall.EACCES
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// See if we have that inode number already in the table
|
||||||
|
// (even if Nlink has dropped to 1)
|
||||||
|
var derivedIVs pathiv.FileIVs
|
||||||
|
v, found := inodeTable.Load(st.Ino)
|
||||||
|
if found {
|
||||||
|
tlog.Debug.Printf("ino%d: newFile: found in the inode table", st.Ino)
|
||||||
|
derivedIVs = v.(pathiv.FileIVs)
|
||||||
|
} else {
|
||||||
|
p := n.Path()
|
||||||
|
derivedIVs = pathiv.DeriveFile(p)
|
||||||
|
// Nlink > 1 means there is more than one path to this file.
|
||||||
|
// Store the derived values so we always return the same data,
|
||||||
|
// regardless of the path that is used to access the file.
|
||||||
|
// This means that the first path wins.
|
||||||
|
if st.Nlink > 1 {
|
||||||
|
v, found = inodeTable.LoadOrStore(st.Ino, derivedIVs)
|
||||||
|
if found {
|
||||||
|
// Another thread has stored a different value before we could.
|
||||||
|
derivedIVs = v.(pathiv.FileIVs)
|
||||||
|
} else {
|
||||||
|
tlog.Debug.Printf("ino%d: newFile: Nlink=%d, stored in the inode table", st.Ino, st.Nlink)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
header := contentenc.FileHeader{
|
||||||
|
Version: contentenc.CurrentVersion,
|
||||||
|
ID: derivedIVs.ID,
|
||||||
|
}
|
||||||
|
fh = &File{
|
||||||
|
fd: os.NewFile(uintptr(fd), fmt.Sprintf("fd%d", fd)),
|
||||||
|
header: header,
|
||||||
|
block0IV: derivedIVs.Block0IV,
|
||||||
|
contentEnc: n.rootNode().contentEnc,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
@ -9,11 +9,10 @@ var _ = (fs.NodeGetattrer)((*Node)(nil))
|
|||||||
var _ = (fs.NodeLookuper)((*Node)(nil))
|
var _ = (fs.NodeLookuper)((*Node)(nil))
|
||||||
var _ = (fs.NodeReaddirer)((*Node)(nil))
|
var _ = (fs.NodeReaddirer)((*Node)(nil))
|
||||||
var _ = (fs.NodeReadlinker)((*Node)(nil))
|
var _ = (fs.NodeReadlinker)((*Node)(nil))
|
||||||
|
|
||||||
/* TODO
|
|
||||||
var _ = (fs.NodeOpener)((*Node)(nil))
|
var _ = (fs.NodeOpener)((*Node)(nil))
|
||||||
|
|
||||||
|
/*
|
||||||
var _ = (fs.NodeStatfser)((*Node)(nil))
|
var _ = (fs.NodeStatfser)((*Node)(nil))
|
||||||
var _ = (fs.NodeMknoder)((*Node)(nil))
|
|
||||||
var _ = (fs.NodeGetxattrer)((*Node)(nil))
|
var _ = (fs.NodeGetxattrer)((*Node)(nil))
|
||||||
var _ = (fs.NodeListxattrer)((*Node)(nil))
|
var _ = (fs.NodeListxattrer)((*Node)(nil))
|
||||||
*/
|
*/
|
||||||
@ -23,6 +22,7 @@ var _ = (fs.NodeOpendirer)((*Node)(nil))
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* Will not implement these - reverse mode is read-only!
|
/* Will not implement these - reverse mode is read-only!
|
||||||
|
var _ = (fs.NodeMknoder)((*Node)(nil))
|
||||||
var _ = (fs.NodeCreater)((*Node)(nil))
|
var _ = (fs.NodeCreater)((*Node)(nil))
|
||||||
var _ = (fs.NodeMkdirer)((*Node)(nil))
|
var _ = (fs.NodeMkdirer)((*Node)(nil))
|
||||||
var _ = (fs.NodeRmdirer)((*Node)(nil))
|
var _ = (fs.NodeRmdirer)((*Node)(nil))
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/hanwen/go-fuse/v2/fs"
|
"github.com/hanwen/go-fuse/v2/fs"
|
||||||
"github.com/hanwen/go-fuse/v2/fuse"
|
"github.com/hanwen/go-fuse/v2/fuse"
|
||||||
|
|
||||||
|
"github.com/rfjakob/gocryptfs/internal/configfile"
|
||||||
"github.com/rfjakob/gocryptfs/internal/pathiv"
|
"github.com/rfjakob/gocryptfs/internal/pathiv"
|
||||||
"github.com/rfjakob/gocryptfs/internal/syscallcompat"
|
"github.com/rfjakob/gocryptfs/internal/syscallcompat"
|
||||||
)
|
)
|
||||||
@ -115,8 +116,8 @@ func (n *Node) lookupLongnameName(ctx context.Context, nameFile string, out *fus
|
|||||||
errno = fs.ToErrno(err)
|
errno = fs.ToErrno(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var vf *virtualFile
|
var vf *VirtualMemNode
|
||||||
vf, errno = n.newVirtualFile([]byte(cFullname), st, inoTagNameFile)
|
vf, errno = n.newVirtualMemNode([]byte(cFullname), st, inoTagNameFile)
|
||||||
if errno != 0 {
|
if errno != 0 {
|
||||||
return nil, errno
|
return nil, errno
|
||||||
}
|
}
|
||||||
@ -141,8 +142,8 @@ func (n *Node) lookupDiriv(ctx context.Context, out *fuse.EntryOut) (ch *fs.Inod
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
content := pathiv.Derive(n.Path(), pathiv.PurposeDirIV)
|
content := pathiv.Derive(n.Path(), pathiv.PurposeDirIV)
|
||||||
var vf *virtualFile
|
var vf *VirtualMemNode
|
||||||
vf, errno = n.newVirtualFile(content, st, inoTagDirIV)
|
vf, errno = n.newVirtualMemNode(content, st, inoTagDirIV)
|
||||||
if errno != 0 {
|
if errno != 0 {
|
||||||
return nil, errno
|
return nil, errno
|
||||||
}
|
}
|
||||||
@ -153,6 +154,30 @@ func (n *Node) lookupDiriv(ctx context.Context, out *fuse.EntryOut) (ch *fs.Inod
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// lookupConf returns a new Inode for the gocryptfs.conf file
|
||||||
|
func (n *Node) lookupConf(ctx context.Context, out *fuse.EntryOut) (ch *fs.Inode, errno syscall.Errno) {
|
||||||
|
rn := n.rootNode()
|
||||||
|
p := filepath.Join(rn.args.Cipherdir, configfile.ConfReverseName)
|
||||||
|
var st syscall.Stat_t
|
||||||
|
err := syscall.Stat(p, &st)
|
||||||
|
if err != nil {
|
||||||
|
errno = fs.ToErrno(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Get unique inode number
|
||||||
|
rn.inoMap.TranslateStat(&st)
|
||||||
|
out.Attr.FromStat(&st)
|
||||||
|
// Create child node
|
||||||
|
id := fs.StableAttr{
|
||||||
|
Mode: uint32(st.Mode),
|
||||||
|
Gen: 1,
|
||||||
|
Ino: st.Ino,
|
||||||
|
}
|
||||||
|
node := &VirtualConfNode{path: p}
|
||||||
|
ch = n.NewInode(ctx, node, id)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// readlink reads and encrypts a symlink. Used by Readlink, Getattr, Lookup.
|
// readlink reads and encrypts a symlink. Used by Readlink, Getattr, Lookup.
|
||||||
func (n *Node) readlink(dirfd int, cName string, pName string) (out []byte, errno syscall.Errno) {
|
func (n *Node) readlink(dirfd int, cName string, pName string) (out []byte, errno syscall.Errno) {
|
||||||
plainTarget, err := syscallcompat.Readlinkat(dirfd, pName)
|
plainTarget, err := syscallcompat.Readlinkat(dirfd, pName)
|
||||||
|
55
internal/fusefrontend_reverse/virtualconf.go
Normal file
55
internal/fusefrontend_reverse/virtualconf.go
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
package fusefrontend_reverse
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"sync"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/hanwen/go-fuse/v2/fs"
|
||||||
|
"github.com/hanwen/go-fuse/v2/fuse"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = (fs.NodeOpener)((*VirtualConfNode)(nil))
|
||||||
|
|
||||||
|
type VirtualConfNode struct {
|
||||||
|
fs.Inode
|
||||||
|
|
||||||
|
path string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *VirtualConfNode) Open(ctx context.Context, flags uint32) (fh fs.FileHandle, fuseFlags uint32, errno syscall.Errno) {
|
||||||
|
fd, err := syscall.Open(n.path, syscall.O_RDONLY, 0)
|
||||||
|
if err != nil {
|
||||||
|
errno = fs.ToErrno(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fh = &VirtualConfFile{fd: fd}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that we have implemented the fs.File* interfaces
|
||||||
|
var _ = (fs.FileReader)((*VirtualConfFile)(nil))
|
||||||
|
var _ = (fs.FileReleaser)((*VirtualConfFile)(nil))
|
||||||
|
|
||||||
|
type VirtualConfFile struct {
|
||||||
|
mu sync.Mutex
|
||||||
|
fd int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *VirtualConfFile) Read(ctx context.Context, buf []byte, off int64) (res fuse.ReadResult, errno syscall.Errno) {
|
||||||
|
f.mu.Lock()
|
||||||
|
defer f.mu.Unlock()
|
||||||
|
res = fuse.ReadResultFd(uintptr(f.fd), off, len(buf))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *VirtualConfFile) Release(ctx context.Context) syscall.Errno {
|
||||||
|
f.mu.Lock()
|
||||||
|
defer f.mu.Unlock()
|
||||||
|
if f.fd != -1 {
|
||||||
|
err := syscall.Close(f.fd)
|
||||||
|
f.fd = -1
|
||||||
|
return fs.ToErrno(err)
|
||||||
|
}
|
||||||
|
return syscall.EBADF
|
||||||
|
}
|
@ -60,7 +60,9 @@ func (n *Node) lookupFileType(cName string) fileType {
|
|||||||
return typeReal
|
return typeReal
|
||||||
}
|
}
|
||||||
|
|
||||||
type virtualFile struct {
|
// VirtualMemNode is an in-memory node that does not have a representation
|
||||||
|
// on disk.
|
||||||
|
type VirtualMemNode struct {
|
||||||
fs.Inode
|
fs.Inode
|
||||||
|
|
||||||
// file content
|
// file content
|
||||||
@ -69,12 +71,12 @@ type virtualFile struct {
|
|||||||
attr fuse.Attr
|
attr fuse.Attr
|
||||||
}
|
}
|
||||||
|
|
||||||
// newVirtualFile creates a new in-memory file that does not have a representation
|
// newVirtualMemNode creates a new in-memory file that does not have a representation
|
||||||
// on disk. "content" is the file content. Timestamps and file owner are copied
|
// on disk. "content" is the file content. Timestamps and file owner are copied
|
||||||
// from "parentFile" (file descriptor).
|
// from "parentFile" (file descriptor).
|
||||||
// For a "gocryptfs.diriv" file, you would use the parent directory as
|
// For a "gocryptfs.diriv" file, you would use the parent directory as
|
||||||
// "parentFile".
|
// "parentFile".
|
||||||
func (n *Node) newVirtualFile(content []byte, parentStat *syscall.Stat_t, inoTag uint8) (vf *virtualFile, errno syscall.Errno) {
|
func (n *Node) newVirtualMemNode(content []byte, parentStat *syscall.Stat_t, inoTag uint8) (vf *VirtualMemNode, errno syscall.Errno) {
|
||||||
if inoTag == 0 {
|
if inoTag == 0 {
|
||||||
log.Panicf("BUG: inoTag for virtual file is zero - this will cause ino collisions!")
|
log.Panicf("BUG: inoTag for virtual file is zero - this will cause ino collisions!")
|
||||||
}
|
}
|
||||||
@ -90,23 +92,23 @@ func (n *Node) newVirtualFile(content []byte, parentStat *syscall.Stat_t, inoTag
|
|||||||
var a fuse.Attr
|
var a fuse.Attr
|
||||||
a.FromStat(st)
|
a.FromStat(st)
|
||||||
|
|
||||||
vf = &virtualFile{content: content, attr: a}
|
vf = &VirtualMemNode{content: content, attr: a}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open - FUSE call
|
// Open - FUSE call
|
||||||
func (f *virtualFile) Open(ctx context.Context, flags uint32) (fh fs.FileHandle, fuseFlags uint32, errno syscall.Errno) {
|
func (f *VirtualMemNode) Open(ctx context.Context, flags uint32) (fh fs.FileHandle, fuseFlags uint32, errno syscall.Errno) {
|
||||||
return nil, fuse.FOPEN_KEEP_CACHE, 0
|
return nil, fuse.FOPEN_KEEP_CACHE, 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAttr - FUSE call
|
// GetAttr - FUSE call
|
||||||
func (f *virtualFile) Getattr(ctx context.Context, fh fs.FileHandle, out *fuse.AttrOut) syscall.Errno {
|
func (f *VirtualMemNode) Getattr(ctx context.Context, fh fs.FileHandle, out *fuse.AttrOut) syscall.Errno {
|
||||||
out.Attr = f.attr
|
out.Attr = f.attr
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read - FUSE call
|
// Read - FUSE call
|
||||||
func (f *virtualFile) Read(ctx context.Context, fh fs.FileHandle, dest []byte, off int64) (fuse.ReadResult, syscall.Errno) {
|
func (f *VirtualMemNode) Read(ctx context.Context, fh fs.FileHandle, dest []byte, off int64) (fuse.ReadResult, syscall.Errno) {
|
||||||
end := int(off) + len(dest)
|
end := int(off) + len(dest)
|
||||||
if end > len(f.content) {
|
if end > len(f.content) {
|
||||||
end = len(f.content)
|
end = len(f.content)
|
Loading…
x
Reference in New Issue
Block a user