/
hotpotato.go
135 lines (110 loc) · 2.62 KB
/
hotpotato.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package HotPotatoFS
import (
"bazil.org/fuse"
"bazil.org/fuse/fs"
"github.com/golang/groupcache"
"io/ioutil"
"log"
"os"
"path/filepath"
"syscall"
)
var filecache *groupcache.Group
func ServeDir(mountpoint string, target string, limit int, me string, peerlist []string) {
peers := groupcache.NewHTTPPool(me)
if peerlist != nil && len(peerlist) > 0 {
peers.Set(peerlist...)
}
filecache = groupcache.NewGroup("filecache", int64(limit)<<20, groupcache.GetterFunc(
func(ctx groupcache.Context, key string, dest groupcache.Sink) error {
contents, err := ioutil.ReadFile(key)
dest.SetBytes(contents)
return err
}))
c, err := fuse.Mount(mountpoint)
if err != nil {
log.Fatal(err)
}
fs.Serve(c, TargetDir{target})
}
type TargetDir struct {
Path string
}
func (nf TargetDir) Root() (fs.Node, fuse.Error) {
return Dir{Node{Path: nf.Path}}, nil
}
type Node struct {
Path string
}
func (n Node) Attr() fuse.Attr {
s, err := os.Stat(n.Path)
if err != nil {
log.Print(err)
return fuse.Attr{}
}
return fuse.Attr{Size: uint64(s.Size()), Mtime: s.ModTime(), Mode: s.Mode()}
}
type Dir struct {
Node
}
func (d Dir) Lookup(name string, intr fs.Intr) (fs fs.Node, error fuse.Error) {
path := filepath.Join(d.Path, name)
s, err := os.Stat(path)
if err != nil {
log.Print(err)
return nil, fuse.ENOENT
}
node := Node{path}
switch {
case s.IsDir():
fs = Dir{node}
case s.Mode().IsRegular():
fs = File{node}
default:
fs = node
}
return
}
func (d Dir) ReadDir(intr fs.Intr) ([]fuse.Dirent, fuse.Error) {
var out []fuse.Dirent
files, err := ioutil.ReadDir(d.Path)
if err != nil {
log.Print(err)
return nil, fuse.Errno(err.(syscall.Errno))
}
for _, node := range files {
de := fuse.Dirent{Name: node.Name()}
if node.IsDir() {
de.Type = fuse.DT_Dir
}
if node.Mode().IsRegular() {
de.Type = fuse.DT_File
}
out = append(out, de)
}
return out, nil
}
type File struct {
Node
}
func (f File) ReadAll(intr fs.Intr) ([]byte, fuse.Error) {
var contents []byte
err := filecache.Get(nil, f.Path, groupcache.AllocatingByteSliceSink(&contents))
if err != nil {
log.Print(err)
return nil, fuse.ENOENT
}
return contents, nil
}
// func (f File) Read(req *fuse.ReadRequest, resp *fuse.ReadResponse, intr fs.Intr) fuse.Error {
// //log.Print("Read Called: ", req, resp, intr)
// //fuse.Debugf = log.Printf
// var dst groupcache.ByteView
// err := filecache.Get(nil, f.Path, groupcache.ByteViewSink(&dst))
// if err != nil {
// log.Print(err)
// return fuse.ENOENT
// }
// resp = &fuse.ReadResponse{Data: dst.Slice(int(req.Offset), int(req.Offset)+req.Size).ByteSlice()}
// return nil
// }