diff --git a/README.md b/README.md index fceab1e..c1b2151 100644 --- a/README.md +++ b/README.md @@ -3,32 +3,35 @@ ### Linux ```shell -$ sudo apt-get install fuse +sudo apt-get install fuse ``` ### MacOSX ```shell -$ brew cask install osxfuse +brew cask install osxfuse ``` ## Build ```shell -$ go get -$ go build -o lot-fuse main.go +go get +go build -o lot-fuse main.go ``` +## Usage + ```shell -$ export LOTPATH=/tmp/mountpoint -$ export LOTBIN=$LOTPATH/bin -$ export PATH=$PATH:$LOTBIN -$ mkdir -p $LOTBIN +export LOTPATH=/tmp/mountpoint +export LOTBIN=$LOTPATH/bin +export PATH=$PATH:$LOTBIN +mkdir -p $LOTBIN ``` ```shell -$ umount $LOTBIN ; go build -o lot-fuse main2.go && ./lot-fuse -fuse.debug $LOTBIN +umount $LOTBIN +./lot-fuse -fuse.debug $LOTBIN ``` ## References diff --git a/main.go b/main.go index 73de3ce..2b2f823 100644 --- a/main.go +++ b/main.go @@ -1,70 +1,157 @@ -// Copyright 2016 the Go-FUSE Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// This program is the analogon of libfuse's hello.c, a a program that -// exposes a single file "file.txt" in the root directory. +// Hellofs implements a simple "hello world" file system. +// https://github.com/ipfs/go-ipfs/blob/master/fuse/readonly/readonly_unix.go package main import ( "context" "flag" + "fmt" "log" + "os" "syscall" - "fmt" - "os" + // "io/ioutil" + "io" + "net/http" - "github.com/hanwen/go-fuse/fs" - "github.com/hanwen/go-fuse/fuse" - fuseversion "github.com/jbenet/go-fuse-version" + "bazil.org/fuse" + "bazil.org/fuse/fs" + // fuseversion "github.com/jbenet/go-fuse-version" + _ "bazil.org/fuse/fs/fstestutil" ) -type HelloRoot struct { - fs.Inode +func usage() { + fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0]) + fmt.Fprintf(os.Stderr, " %s \n", os.Args[0]) + flag.PrintDefaults() } -func (r *HelloRoot) OnAdd(ctx context.Context) { - ch := r.NewPersistentInode( - ctx, &fs.MemRegularFile{ - Data: []byte("file.txt"), - Attr: fuse.Attr{ - Mode: 0644, - }, - }, fs.StableAttr{Ino: 2}) - r.AddChild("file.txt", ch, false) -} +func main() { + flag.Usage = usage + flag.Parse() -func (r *HelloRoot) Getattr(ctx context.Context, fh fs.FileHandle, out *fuse.AttrOut) syscall.Errno { - out.Mode = 0755 - return 0 -} + if flag.NArg() != 1 { + usage() + os.Exit(2) + } + + mountpoint := flag.Arg(0) -var _ = (fs.NodeGetattrer)((*HelloRoot)(nil)) -var _ = (fs.NodeOnAdder)((*HelloRoot)(nil)) + c, err := fuse.Mount( + mountpoint, + fuse.FSName("helloworld"), + fuse.Subtype("hellofs"), + ) + + // sysv, err := fuseversion.LocalFuseSystems() + // if err != nil { + // fmt.Fprintf(os.Stderr, "%s\n", err) + // os.Exit(1) + // } + + // for _, s := range sysv { + // fmt.Printf("Fuse Version %s, %s, %s\n", s.FuseVersion, s.AgentVersion, s.AgentName) + // } -func main() { - sysv, err := fuseversion.LocalFuseSystems() if err != nil { - fmt.Fprintf(os.Stderr, "%s\n", err) - os.Exit(1) + log.Fatal(err) } + defer c.Close() - for _, s := range sysv { - fmt.Printf("Fuse Version %s, %s, %s\n", s.FuseVersion, s.AgentVersion, s.AgentName) + err = fs.Serve(c, FS{}) + if err != nil { + log.Fatal(err) } +} - debug := flag.Bool("debug", false, "print debug data") - flag.Parse() - if len(flag.Args()) < 1 { - log.Fatal("Usage:\n hello MOUNTPOINT") +// FS implements the hello world file system. +type FS struct{} + +func (FS) Root() (fs.Node, error) { + return Dir{}, nil +} + +// Dir implements both Node and Handle for the root directory. +type Dir struct{} + +func (Dir) Attr(ctx context.Context, a *fuse.Attr) error { + a.Inode = 1 + a.Mode = os.ModeDir | 0o555 + return nil +} + +func (Dir) Lookup(ctx context.Context, name string) (fs.Node, error) { + if name == "hello" { + return NewVirtualFile("https://gist.githubusercontent.com/rubeniskov/e8aeec1bebf46696a9b9557e1a1bf936/raw/3fd978bcb6e89274409e5f9eb8ad1e436939c40f/semver-patcher.py"), nil } - opts := &fs.Options{} - opts.Debug = *debug + return nil, syscall.ENOENT +} + +var dirDirs = []fuse.Dirent{ + {Inode: 2, Name: "hello", Type: fuse.DT_File}, +} + +func (Dir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) { + return dirDirs, nil +} + +// File implements both Node and Handle for the hello file. + + + + +// func (File) ReadAll(ctx context.Context) ([]byte, error) { +// resp, err := http.Get("https://gist.githubusercontent.com/rubeniskov/e8aeec1bebf46696a9b9557e1a1bf936/raw/3fd978bcb6e89274409e5f9eb8ad1e436939c40f/semver-patcher.py") +// if err != nil { +// log.Fatal(err) +// } +// defer resp.Body.Close() +// body, err := ioutil.ReadAll(resp.Body) + +// if err != nil { +// log.Fatal(err) +// } + +// fmt.Printf("%s", body) + +// return body, nil +// } - fmt.Printf("Mounting directory %s\n", flag.Arg(0)) - server, err := fs.Mount(flag.Arg(0), &HelloRoot{}, opts) + + +type VirtualFile struct{ + size int64 + body io.Reader +} + + +func NewVirtualFile(locator string) *VirtualFile { + hresp, err := http.Get(locator) if err != nil { - log.Fatalf("Mount fail: %v\n", err) + log.Fatal(err) + } + return &VirtualFile{ + hresp.ContentLength, + hresp.Body, + } +} + +func (vf *VirtualFile) Attr(ctx context.Context, a *fuse.Attr) error { + a.Inode = 2 + a.Mode = 0o555 + a.Size = uint64(vf.size) + return nil +} + +func (vf *VirtualFile) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error { + // Data has a capacity of Size + buf := resp.Data[:int(req.Size)] + n, err := io.ReadFull(vf.body, buf) + resp.Data = buf[:n] + switch err { + case nil, io.EOF, io.ErrUnexpectedEOF: + default: + return err } - server.Wait() + resp.Data = resp.Data[:n] + return nil // may be non-nil / not succeeded } \ No newline at end of file diff --git a/main2.go b/main2.go deleted file mode 100644 index 962fe8a..0000000 --- a/main2.go +++ /dev/null @@ -1,157 +0,0 @@ -// Hellofs implements a simple "hello world" file system. -// https://github.com/ipfs/go-ipfs/blob/master/fuse/readonly/readonly_unix.go -package main - -import ( - "context" - "flag" - "fmt" - "log" - "os" - "syscall" - // "io/ioutil" - "io" - "net/http" - - "bazil.org/fuse" - "bazil.org/fuse/fs" - // fuseversion "github.com/jbenet/go-fuse-version" - _ "bazil.org/fuse/fs/fstestutil" -) - -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 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("helloworld"), - fuse.Subtype("hellofs"), - ) - - // sysv, err := fuseversion.LocalFuseSystems() - // if err != nil { - // fmt.Fprintf(os.Stderr, "%s\n", err) - // os.Exit(1) - // } - - // for _, s := range sysv { - // fmt.Printf("Fuse Version %s, %s, %s\n", s.FuseVersion, s.AgentVersion, s.AgentName) - // } - - if err != nil { - log.Fatal(err) - } - defer c.Close() - - err = fs.Serve(c, FS{}) - if err != nil { - log.Fatal(err) - } -} - -// FS implements the hello world file system. -type FS struct{} - -func (FS) Root() (fs.Node, error) { - return Dir{}, nil -} - -// Dir implements both Node and Handle for the root directory. -type Dir struct{} - -func (Dir) Attr(ctx context.Context, a *fuse.Attr) error { - a.Inode = 1 - a.Mode = os.ModeDir | 0o555 - return nil -} - -func (Dir) Lookup(ctx context.Context, name string) (fs.Node, error) { - if name == "hello" { - return NewVirtualFile("https://gist.githubusercontent.com/rubeniskov/e8aeec1bebf46696a9b9557e1a1bf936/raw/3fd978bcb6e89274409e5f9eb8ad1e436939c40f/semver-patcher.py"), nil - } - return nil, syscall.ENOENT -} - -var dirDirs = []fuse.Dirent{ - {Inode: 2, Name: "hello", Type: fuse.DT_File}, -} - -func (Dir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) { - return dirDirs, nil -} - -// File implements both Node and Handle for the hello file. - - - - -// func (File) ReadAll(ctx context.Context) ([]byte, error) { -// resp, err := http.Get("https://gist.githubusercontent.com/rubeniskov/e8aeec1bebf46696a9b9557e1a1bf936/raw/3fd978bcb6e89274409e5f9eb8ad1e436939c40f/semver-patcher.py") -// if err != nil { -// log.Fatal(err) -// } -// defer resp.Body.Close() -// body, err := ioutil.ReadAll(resp.Body) - -// if err != nil { -// log.Fatal(err) -// } - -// fmt.Printf("%s", body) - -// return body, nil -// } - - - -type VirtualFile struct{ - size int64 - body io.Reader -} - - -func NewVirtualFile(locator string) *VirtualFile { - hresp, err := http.Get(locator) - if err != nil { - log.Fatal(err) - } - return &VirtualFile{ - hresp.ContentLength, - hresp.Body, - } -} - -func (vf *VirtualFile) Attr(ctx context.Context, a *fuse.Attr) error { - a.Inode = 2 - a.Mode = 0o555 - a.Size = uint64(vf.size) - return nil -} - -func (vf *VirtualFile) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error { - // Data has a capacity of Size - buf := resp.Data[:int(req.Size)] - n, err := io.ReadFull(vf.body, buf) - resp.Data = buf[:n] - switch err { - case nil, io.EOF, io.ErrUnexpectedEOF: - default: - return err - } - resp.Data = resp.Data[:n] - return nil // may be non-nil / not succeeded -} \ No newline at end of file