Builds and mounts
This commit is contained in:
parent
8a48609d0e
commit
4b98f74e3e
@ -26,7 +26,7 @@ type FS struct {
|
|||||||
cipherBS int64
|
cipherBS int64
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(key [16]byte) *FS {
|
func NewFS(key [16]byte) *FS {
|
||||||
|
|
||||||
b, err := aes.NewCipher(key[:])
|
b, err := aes.NewCipher(key[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -2,8 +2,19 @@ package frontend
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/rfjakob/gocryptfs/cryptfs"
|
"github.com/rfjakob/gocryptfs/cryptfs"
|
||||||
|
"bazil.org/fuse/fs"
|
||||||
)
|
)
|
||||||
|
|
||||||
type FS struct {
|
type FS struct {
|
||||||
cryptfs.FS
|
*cryptfs.FS
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(key [16]byte) *FS {
|
||||||
|
return &FS {
|
||||||
|
FS: cryptfs.NewFS(key),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs *FS) Root() (fs.Node, error) {
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
395
main.go
Normal file
395
main.go
Normal file
@ -0,0 +1,395 @@
|
|||||||
|
// Memfs implements an in-memory file system.
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"bazil.org/fuse"
|
||||||
|
"bazil.org/fuse/fs"
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
|
||||||
|
"github.com/rfjakob/gocryptfs/frontend"
|
||||||
|
)
|
||||||
|
|
||||||
|
// debug flag enables logging of debug messages to stderr.
|
||||||
|
var debug = flag.Bool("debug", false, "enable debug log messages to stderr")
|
||||||
|
|
||||||
|
func usage() {
|
||||||
|
fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
|
||||||
|
fmt.Fprintf(os.Stderr, " %s MOUNTPOINT\n", os.Args[0])
|
||||||
|
flag.PrintDefaults()
|
||||||
|
}
|
||||||
|
|
||||||
|
func debugLog(msg interface{}) {
|
||||||
|
fmt.Fprintf(os.Stderr, "%v\n", msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
flag.Usage = usage
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
if flag.NArg() != 1 {
|
||||||
|
usage()
|
||||||
|
os.Exit(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
mountpoint := flag.Arg(0)
|
||||||
|
c, err := fuse.Mount(
|
||||||
|
mountpoint,
|
||||||
|
fuse.FSName("memfs"),
|
||||||
|
fuse.Subtype("memfs"),
|
||||||
|
fuse.LocalVolume(),
|
||||||
|
fuse.VolumeName("Memory FS"),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer c.Close()
|
||||||
|
|
||||||
|
cfg := &fs.Config{}
|
||||||
|
if *debug {
|
||||||
|
cfg.Debug = debugLog
|
||||||
|
}
|
||||||
|
|
||||||
|
srv := fs.New(c, cfg)
|
||||||
|
var key [16]byte
|
||||||
|
filesys := frontend.New(key)
|
||||||
|
|
||||||
|
if err := srv.Serve(filesys); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the mount process has an error to report.
|
||||||
|
<-c.Ready
|
||||||
|
if err := c.MountError; err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type MemFS struct {
|
||||||
|
root *Dir
|
||||||
|
nodeId uint64
|
||||||
|
|
||||||
|
nodeCount uint64
|
||||||
|
size int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compile-time interface checks.
|
||||||
|
var _ fs.FS = (*MemFS)(nil)
|
||||||
|
var _ fs.FSStatfser = (*MemFS)(nil)
|
||||||
|
|
||||||
|
var _ fs.Node = (*Dir)(nil)
|
||||||
|
var _ fs.NodeCreater = (*Dir)(nil)
|
||||||
|
var _ fs.NodeMkdirer = (*Dir)(nil)
|
||||||
|
var _ fs.NodeRemover = (*Dir)(nil)
|
||||||
|
var _ fs.NodeRenamer = (*Dir)(nil)
|
||||||
|
var _ fs.NodeStringLookuper = (*Dir)(nil)
|
||||||
|
|
||||||
|
var _ fs.HandleReadAller = (*File)(nil)
|
||||||
|
var _ fs.HandleWriter = (*File)(nil)
|
||||||
|
var _ fs.Node = (*File)(nil)
|
||||||
|
var _ fs.NodeOpener = (*File)(nil)
|
||||||
|
var _ fs.NodeSetattrer = (*File)(nil)
|
||||||
|
|
||||||
|
func NewMemFS() *MemFS {
|
||||||
|
fs := &MemFS{
|
||||||
|
nodeCount: 1,
|
||||||
|
}
|
||||||
|
fs.root = fs.newDir(os.ModeDir | 0777)
|
||||||
|
if fs.root.attr.Inode != 1 {
|
||||||
|
panic("Root node should have been assigned id 1")
|
||||||
|
}
|
||||||
|
return fs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MemFS) nextId() uint64 {
|
||||||
|
return atomic.AddUint64(&m.nodeId, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MemFS) newDir(mode os.FileMode) *Dir {
|
||||||
|
n := time.Now()
|
||||||
|
return &Dir{
|
||||||
|
attr: fuse.Attr{
|
||||||
|
Inode: m.nextId(),
|
||||||
|
Atime: n,
|
||||||
|
Mtime: n,
|
||||||
|
Ctime: n,
|
||||||
|
Crtime: n,
|
||||||
|
Mode: os.ModeDir | mode,
|
||||||
|
},
|
||||||
|
fs: m,
|
||||||
|
nodes: make(map[string]fs.Node),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MemFS) newFile(mode os.FileMode) *File {
|
||||||
|
n := time.Now()
|
||||||
|
return &File{
|
||||||
|
attr: fuse.Attr{
|
||||||
|
Inode: m.nextId(),
|
||||||
|
Atime: n,
|
||||||
|
Mtime: n,
|
||||||
|
Ctime: n,
|
||||||
|
Crtime: n,
|
||||||
|
Mode: mode,
|
||||||
|
},
|
||||||
|
data: make([]byte, 0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Dir struct {
|
||||||
|
sync.RWMutex
|
||||||
|
attr fuse.Attr
|
||||||
|
|
||||||
|
fs *MemFS
|
||||||
|
parent *Dir
|
||||||
|
nodes map[string]fs.Node
|
||||||
|
}
|
||||||
|
|
||||||
|
type File struct {
|
||||||
|
sync.RWMutex
|
||||||
|
attr fuse.Attr
|
||||||
|
|
||||||
|
fs *MemFS
|
||||||
|
data []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *MemFS) Root() (fs.Node, error) {
|
||||||
|
return f.root, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *MemFS) Statfs(ctx context.Context, req *fuse.StatfsRequest,
|
||||||
|
resp *fuse.StatfsResponse) error {
|
||||||
|
resp.Blocks = uint64((atomic.LoadInt64(&f.size) + 511) / 512)
|
||||||
|
resp.Bsize = 512
|
||||||
|
resp.Files = atomic.LoadUint64(&f.nodeCount)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *File) Attr(ctx context.Context, o *fuse.Attr) error {
|
||||||
|
f.RLock()
|
||||||
|
*o = f.attr
|
||||||
|
f.RUnlock()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dir) Attr(ctx context.Context, o *fuse.Attr) error {
|
||||||
|
d.RLock()
|
||||||
|
*o = d.attr
|
||||||
|
d.RUnlock()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dir) Lookup(ctx context.Context, name string) (fs.Node, error) {
|
||||||
|
d.RLock()
|
||||||
|
n, exist := d.nodes[name]
|
||||||
|
d.RUnlock()
|
||||||
|
|
||||||
|
if !exist {
|
||||||
|
return nil, fuse.ENOENT
|
||||||
|
}
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
|
||||||
|
d.RLock()
|
||||||
|
dirs := make([]fuse.Dirent, len(d.nodes)+2)
|
||||||
|
|
||||||
|
// Add special references.
|
||||||
|
dirs[0] = fuse.Dirent{
|
||||||
|
Name: ".",
|
||||||
|
Inode: d.attr.Inode,
|
||||||
|
Type: fuse.DT_Dir,
|
||||||
|
}
|
||||||
|
dirs[1] = fuse.Dirent{
|
||||||
|
Name: "..",
|
||||||
|
Type: fuse.DT_Dir,
|
||||||
|
}
|
||||||
|
if d.parent != nil {
|
||||||
|
dirs[1].Inode = d.parent.attr.Inode
|
||||||
|
} else {
|
||||||
|
dirs[1].Inode = d.attr.Inode
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add remaining files.
|
||||||
|
idx := 2
|
||||||
|
for name, node := range d.nodes {
|
||||||
|
ent := fuse.Dirent{
|
||||||
|
Name: name,
|
||||||
|
}
|
||||||
|
switch n := node.(type) {
|
||||||
|
case *File:
|
||||||
|
ent.Inode = n.attr.Inode
|
||||||
|
ent.Type = fuse.DT_File
|
||||||
|
case *Dir:
|
||||||
|
ent.Inode = n.attr.Inode
|
||||||
|
ent.Type = fuse.DT_Dir
|
||||||
|
}
|
||||||
|
dirs[idx] = ent
|
||||||
|
idx++
|
||||||
|
}
|
||||||
|
d.RUnlock()
|
||||||
|
return dirs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dir) Mkdir(ctx context.Context, req *fuse.MkdirRequest) (fs.Node, error) {
|
||||||
|
d.Lock()
|
||||||
|
defer d.Unlock()
|
||||||
|
|
||||||
|
if _, exists := d.nodes[req.Name]; exists {
|
||||||
|
return nil, fuse.EEXIST
|
||||||
|
}
|
||||||
|
|
||||||
|
n := d.fs.newDir(req.Mode)
|
||||||
|
d.nodes[req.Name] = n
|
||||||
|
atomic.AddUint64(&d.fs.nodeCount, 1)
|
||||||
|
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dir) Create(ctx context.Context, req *fuse.CreateRequest,
|
||||||
|
resp *fuse.CreateResponse) (fs.Node, fs.Handle, error) {
|
||||||
|
d.Lock()
|
||||||
|
defer d.Unlock()
|
||||||
|
|
||||||
|
if _, exists := d.nodes[req.Name]; exists {
|
||||||
|
return nil, nil, fuse.EEXIST
|
||||||
|
}
|
||||||
|
|
||||||
|
n := d.fs.newFile(req.Mode)
|
||||||
|
n.fs = d.fs
|
||||||
|
d.nodes[req.Name] = n
|
||||||
|
atomic.AddUint64(&d.fs.nodeCount, 1)
|
||||||
|
|
||||||
|
resp.Attr = n.attr
|
||||||
|
|
||||||
|
return n, n, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dir) Rename(ctx context.Context, req *fuse.RenameRequest, newDir fs.Node) error {
|
||||||
|
nd := newDir.(*Dir)
|
||||||
|
if d.attr.Inode == nd.attr.Inode {
|
||||||
|
d.Lock()
|
||||||
|
defer d.Unlock()
|
||||||
|
} else if d.attr.Inode < nd.attr.Inode {
|
||||||
|
d.Lock()
|
||||||
|
defer d.Unlock()
|
||||||
|
nd.Lock()
|
||||||
|
defer nd.Unlock()
|
||||||
|
} else {
|
||||||
|
nd.Lock()
|
||||||
|
defer nd.Unlock()
|
||||||
|
d.Lock()
|
||||||
|
defer d.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, exists := d.nodes[req.OldName]; !exists {
|
||||||
|
return fuse.ENOENT
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rename can be used as an atomic replace, override an existing file.
|
||||||
|
if old, exists := nd.nodes[req.NewName]; exists {
|
||||||
|
atomic.AddUint64(&d.fs.nodeCount, ^uint64(0)) // decrement by one
|
||||||
|
if oldFile, ok := old.(*File); !ok {
|
||||||
|
atomic.AddInt64(&d.fs.size, -int64(oldFile.attr.Size))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nd.nodes[req.NewName] = d.nodes[req.OldName]
|
||||||
|
delete(d.nodes, req.OldName)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dir) Remove(ctx context.Context, req *fuse.RemoveRequest) error {
|
||||||
|
d.Lock()
|
||||||
|
defer d.Unlock()
|
||||||
|
|
||||||
|
if n, exists := d.nodes[req.Name]; !exists {
|
||||||
|
return fuse.ENOENT
|
||||||
|
} else if req.Dir && len(n.(*Dir).nodes) > 0 {
|
||||||
|
return fuse.ENOTEMPTY
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(d.nodes, req.Name)
|
||||||
|
atomic.AddUint64(&d.fs.nodeCount, ^uint64(0)) // decrement by one
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *File) Open(ctx context.Context, req *fuse.OpenRequest, resp *fuse.OpenResponse) (fs.Handle,
|
||||||
|
error) {
|
||||||
|
return f, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *File) ReadAll(ctx context.Context) ([]byte, error) {
|
||||||
|
f.RLock()
|
||||||
|
out := make([]byte, len(f.data))
|
||||||
|
copy(out, f.data)
|
||||||
|
f.RUnlock()
|
||||||
|
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *File) Write(ctx context.Context, req *fuse.WriteRequest, resp *fuse.WriteResponse) error {
|
||||||
|
f.Lock()
|
||||||
|
|
||||||
|
l := len(req.Data)
|
||||||
|
end := int(req.Offset) + l
|
||||||
|
if end > len(f.data) {
|
||||||
|
delta := end - len(f.data)
|
||||||
|
f.data = append(f.data, make([]byte, delta)...)
|
||||||
|
f.attr.Size = uint64(len(f.data))
|
||||||
|
atomic.AddInt64(&f.fs.size, int64(delta))
|
||||||
|
}
|
||||||
|
copy(f.data[req.Offset:end], req.Data)
|
||||||
|
resp.Size = l
|
||||||
|
|
||||||
|
f.Unlock()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *File) Setattr(ctx context.Context, req *fuse.SetattrRequest,
|
||||||
|
resp *fuse.SetattrResponse) error {
|
||||||
|
f.Lock()
|
||||||
|
|
||||||
|
if req.Valid.Size() {
|
||||||
|
delta := int(req.Size) - len(f.data)
|
||||||
|
if delta > 0 {
|
||||||
|
f.data = append(f.data, make([]byte, delta)...)
|
||||||
|
} else {
|
||||||
|
f.data = f.data[0:req.Size]
|
||||||
|
}
|
||||||
|
f.attr.Size = req.Size
|
||||||
|
atomic.AddInt64(&f.fs.size, int64(delta))
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.Valid.Mode() {
|
||||||
|
f.attr.Mode = req.Mode
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.Valid.Atime() {
|
||||||
|
f.attr.Atime = req.Atime
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.Valid.AtimeNow() {
|
||||||
|
f.attr.Atime = time.Now()
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.Valid.Mtime() {
|
||||||
|
f.attr.Mtime = req.Mtime
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.Valid.MtimeNow() {
|
||||||
|
f.attr.Mtime = time.Now()
|
||||||
|
}
|
||||||
|
|
||||||
|
resp.Attr = f.attr
|
||||||
|
|
||||||
|
f.Unlock()
|
||||||
|
return nil
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user