123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269 |
- // Copyright 2015 Google Inc. All Rights Reserved.
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- package hellofs
- import (
- "io"
- "os"
- "strings"
- "golang.org/x/net/context"
- "github.com/jacobsa/fuse"
- "github.com/jacobsa/fuse/fuseops"
- "github.com/jacobsa/fuse/fuseutil"
- "github.com/jacobsa/timeutil"
- )
- // Create a file system with a fixed structure that looks like this:
- //
- // hello
- // dir/
- // world
- //
- // Each file contains the string "Hello, world!".
- func NewHelloFS(clock timeutil.Clock) (server fuse.Server, err error) {
- fs := &helloFS{
- Clock: clock,
- }
- server = fuseutil.NewFileSystemServer(fs)
- return
- }
- type helloFS struct {
- fuseutil.NotImplementedFileSystem
- Clock timeutil.Clock
- }
- const (
- rootInode fuseops.InodeID = fuseops.RootInodeID + iota
- helloInode
- dirInode
- worldInode
- )
- type inodeInfo struct {
- attributes fuseops.InodeAttributes
- // File or directory?
- dir bool
- // For directories, children.
- children []fuseutil.Dirent
- }
- // We have a fixed directory structure.
- var gInodeInfo = map[fuseops.InodeID]inodeInfo{
- // root
- rootInode: inodeInfo{
- attributes: fuseops.InodeAttributes{
- Nlink: 1,
- Mode: 0555 | os.ModeDir,
- },
- dir: true,
- 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,
- },
- },
- },
- // hello
- helloInode: inodeInfo{
- attributes: fuseops.InodeAttributes{
- Nlink: 1,
- Mode: 0444,
- Size: uint64(len("Hello, world!")),
- },
- },
- // dir
- dirInode: inodeInfo{
- attributes: fuseops.InodeAttributes{
- Nlink: 1,
- Mode: 0555 | os.ModeDir,
- },
- dir: true,
- children: []fuseutil.Dirent{
- fuseutil.Dirent{
- Offset: 1,
- Inode: worldInode,
- Name: "world",
- Type: fuseutil.DT_File,
- },
- },
- },
- // world
- worldInode: inodeInfo{
- attributes: fuseops.InodeAttributes{
- Nlink: 1,
- Mode: 0444,
- Size: uint64(len("Hello, world!")),
- },
- },
- }
- func findChildInode(
- name string,
- children []fuseutil.Dirent) (inode fuseops.InodeID, err error) {
- for _, e := range children {
- if e.Name == name {
- inode = e.Inode
- return
- }
- }
- err = fuse.ENOENT
- return
- }
- func (fs *helloFS) patchAttributes(
- attr *fuseops.InodeAttributes) {
- now := fs.Clock.Now()
- attr.Atime = now
- attr.Mtime = now
- attr.Crtime = now
- }
- func (fs *helloFS) StatFS(
- ctx context.Context,
- op *fuseops.StatFSOp) (err error) {
- return
- }
- func (fs *helloFS) LookUpInode(
- ctx context.Context,
- op *fuseops.LookUpInodeOp) (err error) {
- // Find the info for the parent.
- parentInfo, ok := gInodeInfo[op.Parent]
- if !ok {
- err = fuse.ENOENT
- return
- }
- // Find the child within the parent.
- childInode, err := findChildInode(op.Name, parentInfo.children)
- if err != nil {
- return
- }
- // Copy over information.
- op.Entry.Child = childInode
- op.Entry.Attributes = gInodeInfo[childInode].attributes
- // Patch attributes.
- fs.patchAttributes(&op.Entry.Attributes)
- return
- }
- func (fs *helloFS) GetInodeAttributes(
- ctx context.Context,
- op *fuseops.GetInodeAttributesOp) (err error) {
- // Find the info for this inode.
- info, ok := gInodeInfo[op.Inode]
- if !ok {
- err = fuse.ENOENT
- return
- }
- // Copy over its attributes.
- op.Attributes = info.attributes
- // Patch attributes.
- fs.patchAttributes(&op.Attributes)
- return
- }
- func (fs *helloFS) OpenDir(
- ctx context.Context,
- op *fuseops.OpenDirOp) (err error) {
- // Allow opening any directory.
- return
- }
- func (fs *helloFS) ReadDir(
- ctx context.Context,
- op *fuseops.ReadDirOp) (err error) {
- // Find the info for this inode.
- info, ok := gInodeInfo[op.Inode]
- if !ok {
- err = fuse.ENOENT
- return
- }
- if !info.dir {
- err = fuse.EIO
- return
- }
- entries := info.children
- // Grab the range of interest.
- if op.Offset > fuseops.DirOffset(len(entries)) {
- err = fuse.EIO
- return
- }
- entries = entries[op.Offset:]
- // Resume at the specified offset into the array.
- for _, e := range entries {
- n := fuseutil.WriteDirent(op.Dst[op.BytesRead:], e)
- if n == 0 {
- break
- }
- op.BytesRead += n
- }
- return
- }
- func (fs *helloFS) OpenFile(
- ctx context.Context,
- op *fuseops.OpenFileOp) (err error) {
- // Allow opening any file.
- return
- }
- func (fs *helloFS) ReadFile(
- ctx context.Context,
- op *fuseops.ReadFileOp) (err error) {
- // Let io.ReaderAt deal with the semantics.
- reader := strings.NewReader("Hello, world!")
- op.BytesRead, err = reader.ReadAt(op.Dst, op.Offset)
- // Special case: FUSE doesn't expect us to return io.EOF.
- if err == io.EOF {
- err = nil
- }
- return
- }
|