memnode.go 4.56 KB
Newer Older
1 2 3 4 5 6 7
package fuse

import (
	"fmt"
	"log"
	"os"
	"sync"
8
	"syscall"
9 10 11 12 13 14 15
	"time"
)

var _ = log.Println

type MemNodeFs struct {
	DefaultNodeFileSystem
16
	backingStorePrefix string
Han-Wen Nienhuys's avatar
Han-Wen Nienhuys committed
17
	root               *memNode
18

Han-Wen Nienhuys's avatar
Han-Wen Nienhuys committed
19
	mutex    sync.Mutex
20 21 22
	nextFree int
}

23 24
func (fs *MemNodeFs) String() string {
	return fmt.Sprintf("MemNodeFs(%s)", fs.backingStorePrefix)
25 26
}

27 28
func (fs *MemNodeFs) Root() FsNode {
	return fs.root
29 30
}

31 32
func (fs *MemNodeFs) newNode() *memNode {
	fs.mutex.Lock()
33
	n := &memNode{
34 35
		fs: fs,
		id: fs.nextFree,
36
	}
37 38
	now := time.Now()
	n.info.SetTimes(&now, &now, &now)
39
	n.info.Mode = S_IFDIR | 0777
40
	fs.nextFree++
41
	fs.mutex.Unlock()
42 43 44
	return n
}

45
func NewMemNodeFs(prefix string) *MemNodeFs {
46
	me := &MemNodeFs{}
47
	me.backingStorePrefix = prefix
48 49 50 51
	me.root = me.newNode()
	return me
}

52
func (fs *MemNodeFs) Filename(n *Inode) string {
53 54 55 56 57 58 59
	mn := n.FsNode().(*memNode)
	return mn.filename()
}

type memNode struct {
	DefaultFsNode
	fs *MemNodeFs
Han-Wen Nienhuys's avatar
Han-Wen Nienhuys committed
60 61 62
	id int

	link string
63
	info Attr
64 65
}

66 67 68 69
func (n *memNode) newNode(isdir bool) *memNode {
	newNode := n.fs.newNode()
	n.Inode().New(isdir, newNode)
	return newNode
70 71
}

72 73
func (n *memNode) filename() string {
	return fmt.Sprintf("%s%d", n.fs.backingStorePrefix, n.id)
74 75
}

76
func (n *memNode) Deletable() bool {
77
	return false
78 79
}

80 81
func (n *memNode) Readlink(c *Context) ([]byte, Status) {
	return []byte(n.link), OK
82 83
}

84
func (n *memNode) Mkdir(name string, mode uint32, context *Context) (newNode FsNode, code Status) {
85 86 87
	ch := n.newNode(true)
	ch.info.Mode = mode | S_IFDIR
	n.Inode().AddChild(name, ch.Inode())
88
	return ch, OK
89 90
}

91 92
func (n *memNode) Unlink(name string, context *Context) (code Status) {
	ch := n.Inode().RmChild(name)
93 94 95 96 97 98
	if ch == nil {
		return ENOENT
	}
	return OK
}

99 100
func (n *memNode) Rmdir(name string, context *Context) (code Status) {
	return n.Unlink(name, context)
101 102
}

103
func (n *memNode) Symlink(name string, content string, context *Context) (newNode FsNode, code Status) {
104 105 106 107
	ch := n.newNode(false)
	ch.info.Mode = S_IFLNK | 0777
	ch.link = content
	n.Inode().AddChild(name, ch.Inode())
Han-Wen Nienhuys's avatar
Han-Wen Nienhuys committed
108

109
	return ch, OK
110 111
}

112 113
func (n *memNode) Rename(oldName string, newParent FsNode, newName string, context *Context) (code Status) {
	ch := n.Inode().RmChild(oldName)
114 115 116 117 118
	newParent.Inode().RmChild(newName)
	newParent.Inode().AddChild(newName, ch)
	return OK
}

119
func (n *memNode) Link(name string, existing FsNode, context *Context) (newNode FsNode, code Status) {
120
	n.Inode().AddChild(name, existing.Inode())
121
	return existing, code
122 123
}

124
func (n *memNode) Create(name string, flags uint32, mode uint32, context *Context) (file File, newNode FsNode, code Status) {
125 126
	ch := n.newNode(false)
	ch.info.Mode = mode | S_IFREG
Han-Wen Nienhuys's avatar
Han-Wen Nienhuys committed
127

128
	f, err := os.Create(ch.filename())
129
	if err != nil {
130
		return nil, nil, ToStatus(err)
131
	}
132
	n.Inode().AddChild(name, ch.Inode())
133
	return ch.newFile(f), ch, OK
134 135 136 137 138 139 140
}

type memNodeFile struct {
	LoopbackFile
	node *memNode
}

141 142
func (n *memNodeFile) String() string {
	return fmt.Sprintf("memNodeFile(%s)", n.LoopbackFile.String())
143 144
}

145 146
func (n *memNodeFile) InnerFile() File {
	return &n.LoopbackFile
147 148
}

149 150
func (n *memNodeFile) Flush() Status {
	code := n.LoopbackFile.Flush()
151 152 153 154 155 156 157 158 159 160

	if !code.Ok() {
		return code
	}

	st := syscall.Stat_t{}
	err := syscall.Stat(n.node.filename(), &st)
	n.node.info.Size = uint64(st.Size)
	n.node.info.Blocks = uint64(st.Blocks)
	return ToStatus(err)
161 162
}

163
func (n *memNode) newFile(f *os.File) File {
164 165
	return &memNodeFile{
		LoopbackFile: LoopbackFile{File: f},
166
		node:         n,
167
	}
168 169
}

170 171
func (n *memNode) Open(flags uint32, context *Context) (file File, code Status) {
	f, err := os.OpenFile(n.filename(), int(flags), 0666)
172
	if err != nil {
173
		return nil, ToStatus(err)
174 175
	}

176
	return n.newFile(f), OK
177 178
}

179 180 181
func (n *memNode) GetAttr(fi *Attr, file File, context *Context) (code Status) {
	*fi = n.info
	return OK
182 183
}

184
func (n *memNode) Truncate(file File, size uint64, context *Context) (code Status) {
185
	if file != nil {
186 187
		code = file.Truncate(size)
	} else {
188
		err := os.Truncate(n.filename(), int64(size))
189
		code = ToStatus(err)
190
	}
191
	if code.Ok() {
192 193
		now := time.Now()
		n.info.SetTimes(nil, nil, &now)
194
		// TODO - should update mtime too?
195
		n.info.Size = size
196 197
	}
	return code
198 199
}

200 201 202
func (n *memNode) Utimens(file File, atime *time.Time, mtime *time.Time, context *Context) (code Status) {
	c := time.Now()
	n.info.SetTimes(atime, mtime, &c)
203 204 205
	return OK
}

206 207
func (n *memNode) Chmod(file File, perms uint32, context *Context) (code Status) {
	n.info.Mode = (n.info.Mode ^ 07777) | perms
208 209
	now := time.Now()
	n.info.SetTimes(nil, nil, &now)
210 211 212
	return OK
}

213 214 215
func (n *memNode) Chown(file File, uid uint32, gid uint32, context *Context) (code Status) {
	n.info.Uid = uid
	n.info.Gid = gid
216 217
	now := time.Now()
	n.info.SetTimes(nil, nil, &now)
218 219
	return OK
}