fusego/samples/hello_fs.go

230 lines
4.2 KiB
Go
Raw Normal View History

// Copyright 2015 Google Inc. All Rights Reserved.
// Author: jacobsa@google.com (Aaron Jacobs)
package samples
import (
2015-02-27 05:44:51 +03:00
"os"
2015-02-27 00:57:18 +03:00
"github.com/jacobsa/fuse"
"github.com/jacobsa/fuse/fuseutil"
"github.com/jacobsa/gcsfuse/timeutil"
"golang.org/x/net/context"
)
// A file system with a fixed structure that looks like this:
//
// hello
// dir/
// world
//
// Each file contains the string "Hello, world!".
type HelloFS struct {
fuseutil.NotImplementedFileSystem
Clock timeutil.Clock
}
2015-02-27 00:57:18 +03:00
var _ fuse.FileSystem = &HelloFS{}
2015-02-27 03:55:00 +03:00
const (
rootInode fuse.InodeID = fuse.RootInodeID + iota
helloInode
dirInode
worldInode
)
2015-02-27 05:35:16 +03:00
type inodeInfo struct {
2015-02-27 05:36:20 +03:00
attributes fuse.InodeAttributes
2015-02-27 05:35:16 +03:00
// File or directory?
dir bool
// For directories, children.
children []fuseutil.Dirent
}
// We have a fixed directory structure.
var gInodeInfo = map[fuse.InodeID]inodeInfo{
// root
rootInode: inodeInfo{
2015-02-27 05:44:51 +03:00
attributes: fuse.InodeAttributes{
2015-02-27 05:52:43 +03:00
// TODO(jacobsa): Why do we get premission denied errors when this is
// 0500?
Mode: 0555 | os.ModeDir,
2015-02-27 05:44:51 +03:00
},
dir: true,
2015-02-27 05:35:16 +03:00
children: []fuseutil.Dirent{
fuseutil.Dirent{
Offset: 1,
Inode: helloInode,
Name: "hello",
Type: fuseutil.DT_File,
},
fuseutil.Dirent{
Offset: 2,
Inode: dirInode,
Name: "dir",
Type: fuseutil.DT_Directory,
},
},
},
2015-02-27 05:52:43 +03:00
// hello
helloInode: inodeInfo{
attributes: fuse.InodeAttributes{
Mode: 0400,
2015-02-27 06:03:38 +03:00
Size: uint64(len("Hello, world!")),
2015-02-27 05:52:43 +03:00
},
},
2015-02-27 06:00:18 +03:00
// dir
dirInode: inodeInfo{
attributes: fuse.InodeAttributes{
Mode: 0500 | os.ModeDir,
},
dir: true,
children: []fuseutil.Dirent{
fuseutil.Dirent{
Offset: 1,
Inode: worldInode,
Name: "world",
Type: fuseutil.DT_File,
},
},
},
2015-02-27 06:03:38 +03:00
// world
worldInode: inodeInfo{
attributes: fuse.InodeAttributes{
Mode: 0400,
Size: uint64(len("Hello, world!")),
},
},
2015-02-27 05:35:16 +03:00
}
2015-02-27 05:56:51 +03:00
func findChildInode(
name string,
children []fuseutil.Dirent) (inode fuse.InodeID, err error) {
for _, e := range children {
if e.Name == name {
inode = e.Inode
return
}
}
err = fuse.ENOENT
return
}
2015-02-27 06:24:31 +03:00
func (fs *HelloFS) patchAttributes(
attr *fuse.InodeAttributes) {
now := fs.Clock.Now()
attr.Atime = now
attr.Mtime = now
attr.Crtime = now
}
2015-02-27 05:56:51 +03:00
func (fs *HelloFS) LookUpInode(
ctx context.Context,
req *fuse.LookUpInodeRequest) (
resp *fuse.LookUpInodeResponse, err error) {
resp = &fuse.LookUpInodeResponse{}
// Find the info for the parent.
parentInfo, ok := gInodeInfo[req.Parent]
if !ok {
err = fuse.ENOENT
return
}
// Find the child within the parent.
childInode, err := findChildInode(req.Name, parentInfo.children)
if err != nil {
return
}
// Copy over information.
resp.Child = childInode
resp.Attributes = gInodeInfo[childInode].attributes
2015-02-27 06:05:52 +03:00
// Patch attributes.
2015-02-27 06:24:31 +03:00
fs.patchAttributes(&resp.Attributes)
2015-02-27 06:05:52 +03:00
2015-02-27 05:56:51 +03:00
return
}
func (fs *HelloFS) GetInodeAttributes(
ctx context.Context,
req *fuse.GetInodeAttributesRequest) (
resp *fuse.GetInodeAttributesResponse, err error) {
resp = &fuse.GetInodeAttributesResponse{}
// Find the info for this inode.
info, ok := gInodeInfo[req.Inode]
if !ok {
err = fuse.ENOENT
return
}
// Copy over its attributes.
resp.Attributes = info.attributes
2015-02-27 06:05:52 +03:00
// Patch attributes.
2015-02-27 06:24:31 +03:00
fs.patchAttributes(&resp.Attributes)
2015-02-27 06:05:52 +03:00
return
}
2015-02-27 01:56:27 +03:00
func (fs *HelloFS) OpenDir(
ctx context.Context,
2015-02-27 01:56:27 +03:00
req *fuse.OpenDirRequest) (resp *fuse.OpenDirResponse, err error) {
// We always allow opening the root directory.
2015-02-27 03:55:00 +03:00
if req.Inode == rootInode {
2015-02-27 01:56:57 +03:00
resp = &fuse.OpenDirResponse{}
return
}
// TODO(jacobsa): Handle others.
2015-02-27 00:57:18 +03:00
err = fuse.ENOSYS
return
}
2015-02-27 04:21:12 +03:00
func (fs *HelloFS) ReadDir(
ctx context.Context,
req *fuse.ReadDirRequest) (resp *fuse.ReadDirResponse, err error) {
resp = &fuse.ReadDirResponse{}
2015-02-27 05:35:16 +03:00
// Find the info for this inode.
info, ok := gInodeInfo[req.Inode]
2015-02-27 04:21:12 +03:00
if !ok {
err = fuse.ENOENT
return
}
2015-02-27 05:35:16 +03:00
if !info.dir {
err = fuse.EIO
return
}
entries := info.children
2015-02-27 04:38:27 +03:00
// Grab the range of interest.
if req.Offset > fuse.DirOffset(len(entries)) {
2015-02-27 04:21:12 +03:00
err = fuse.EIO
return
}
2015-02-27 04:38:27 +03:00
entries = entries[req.Offset:]
2015-02-27 04:21:12 +03:00
// Resume at the specified offset into the array.
for _, e := range entries {
resp.Data = fuseutil.AppendDirent(resp.Data, e)
if len(resp.Data) > req.Size {
2015-02-27 04:21:12 +03:00
resp.Data = resp.Data[:req.Size]
break
}
}
return
}