diff options
Diffstat (limited to 'internal/fusefrontend_reverse/virtualfile.go')
-rw-r--r-- | internal/fusefrontend_reverse/virtualfile.go | 100 |
1 files changed, 100 insertions, 0 deletions
diff --git a/internal/fusefrontend_reverse/virtualfile.go b/internal/fusefrontend_reverse/virtualfile.go index a92c127..a7f6913 100644 --- a/internal/fusefrontend_reverse/virtualfile.go +++ b/internal/fusefrontend_reverse/virtualfile.go @@ -1,7 +1,16 @@ package fusefrontend_reverse import ( + "context" + "log" "syscall" + + "github.com/hanwen/go-fuse/v2/fs" + "github.com/hanwen/go-fuse/v2/fuse" + + "github.com/rfjakob/gocryptfs/internal/configfile" + "github.com/rfjakob/gocryptfs/internal/inomap" + "github.com/rfjakob/gocryptfs/internal/nametransform" ) const ( @@ -13,3 +22,94 @@ const ( inoTagDirIV = 1 inoTagNameFile = 2 ) + +type fileType int + +// Values returned by lookupFileType +const ( + // A real file/directory/symlink in the backing plaintext directory + typeReal fileType = iota + // A DirIV (gocryptfs.diriv) file + typeDiriv + // A gocryptfs.longname.*.name file for a file with a long name + typeName + // The config file gocryptfs.conf + typeConfig +) + +// lookupFileType returns the type of child file name +// (one of the fileType constants above). Called from Lookup(). +func (n *Node) lookupFileType(cName string) fileType { + rn := n.rootNode() + // In -plaintextname mode, neither diriv nor longname files exist. + if !rn.args.PlaintextNames { + // Is it a gocryptfs.diriv file? + if cName == nametransform.DirIVFilename { + return typeDiriv + } + // Is it a gocryptfs.longname.*.name file? + if t := nametransform.NameType(cName); t == nametransform.LongNameFilename { + return typeName + } + } + // gocryptfs.conf in the root directory. This is passed through to + // .gocryptfs.reverse.conf in the backing plaintext directory. + if n.isRoot() && !rn.args.ConfigCustom && cName == configfile.ConfDefaultName { + return typeConfig + } + return typeReal +} + +type virtualFile struct { + fs.Inode + + // file content + content []byte + // attributes for Getattr() + attr fuse.Attr +} + +// newVirtualFile 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 +// from "parentFile" (file descriptor). +// For a "gocryptfs.diriv" file, you would use the parent directory as +// "parentFile". +func (n *Node) newVirtualFile(content []byte, parentStat *syscall.Stat_t, inoTag uint8) (vf *virtualFile, errno syscall.Errno) { + if inoTag == 0 { + log.Panicf("BUG: inoTag for virtual file is zero - this will cause ino collisions!") + } + + // Adjust inode number and size + rn := n.rootNode() + st := parentStat + q := inomap.NewQIno(uint64(st.Dev), inoTag, uint64(st.Ino)) + st.Ino = rn.inoMap.Translate(q) + st.Size = int64(len(content)) + st.Mode = virtualFileMode + st.Nlink = 1 + var a fuse.Attr + a.FromStat(st) + + vf = &virtualFile{content: content, attr: a} + return +} + +// Open - FUSE call +func (f *virtualFile) Open(ctx context.Context, flags uint32) (fh fs.FileHandle, fuseFlags uint32, errno syscall.Errno) { + return nil, fuse.FOPEN_KEEP_CACHE, 0 +} + +// GetAttr - FUSE call +func (f *virtualFile) Getattr(ctx context.Context, fh fs.FileHandle, out *fuse.AttrOut) syscall.Errno { + out.Attr = f.attr + return 0 +} + +// Read - FUSE call +func (f *virtualFile) Read(ctx context.Context, fh fs.FileHandle, dest []byte, off int64) (fuse.ReadResult, syscall.Errno) { + end := int(off) + len(dest) + if end > len(f.content) { + end = len(f.content) + } + return fuse.ReadResultData(f.content[off:end]), 0 +} |