Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
License: MIT
Signed-off-by: Dominic Della Valle <ddvpublic@gmail.com>
  • Loading branch information
djdv committed Dec 4, 2018
1 parent 481136b commit ec5978c
Show file tree
Hide file tree
Showing 23 changed files with 2,646 additions and 149 deletions.
7 changes: 7 additions & 0 deletions cmd/ipfs/Rules.mk
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ CLEAN += $(IPFS_BIN_$(d))

PATH := $(realpath $(d)):$(PATH)

#TODO: review; probably a more elegant way to do this; alternative is fork cgofuse, removing cgo invocations
ifeq ($(WINDOWS),1)
ifeq ($(origin CPATH), undefined)
export CGO_ENABLED = 0
endif
endif

# disabled for now
# depend on *.pb.go files in the repo as Order Only (as they shouldn't be rebuilt if exist)
# DPES_OO_$(d) := diagnostics/pb/diagnostics.pb.go exchange/bitswap/message/pb/message.pb.go
Expand Down
151 changes: 151 additions & 0 deletions core/commands/mount.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
// +build !nofuse

package commands

import (
"errors"
"fmt"
"path/filepath"

"github.com/billziss-gh/cgofuse/fuse"
cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv"
mi "github.com/ipfs/go-ipfs/core/commands/mount"

cmds "gx/ipfs/Qma6uuSyjkecGhMFFLfzyJDPyoDtNJSHJNweDccZhaWkgU/go-ipfs-cmds"
cmdkit "gx/ipfs/Qmde5VP1qUkyQXKCfmEUA7bP64V2HAptbJ7phuPp7jXWwg/go-ipfs-cmdkit"
)

var MountCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "Mounts IPFS to the filesystem.",
ShortDescription: `
Mount IPFS at a read-only mountpoint on the OS (default: /ipfs and /ipns).
All IPFS objects will be accessible under that directory. Note that the
root will not be listable, as it is virtual. Access known paths directly.
You may have to create /ipfs and /ipns before using 'ipfs mount':
> sudo mkdir /ipfs /ipns
> sudo chown $(whoami) /ipfs /ipns
> ipfs daemon &
> ipfs mount
`,
LongDescription: `
Mount IPFS at a read-only mountpoint on the OS. The default, /ipfs and /ipns,
are set in the configuration file, but can be overriden by the options.
All IPFS objects will be accessible under this directory. Note that the
root will not be listable, as it is virtual. Access known paths directly.
You may have to create /ipfs and /ipns before using 'ipfs mount':
> sudo mkdir /ipfs /ipns
> sudo chown $(whoami) /ipfs /ipns
> ipfs daemon &
> ipfs mount
Example:
# setup
> mkdir foo
> echo "baz" > foo/bar
> ipfs add -r foo
added QmWLdkp93sNxGRjnFHPaYg8tCQ35NBY3XPn6KiETd3Z4WR foo/bar
added QmSh5e7S6fdcu75LAbXNZAFY2nGyZUJXyLCJDvn2zRkWyC foo
> ipfs ls QmSh5e7S6fdcu75LAbXNZAFY2nGyZUJXyLCJDvn2zRkWyC
QmWLdkp93sNxGRjnFHPaYg8tCQ35NBY3XPn6KiETd3Z4WR 12 bar
> ipfs cat QmWLdkp93sNxGRjnFHPaYg8tCQ35NBY3XPn6KiETd3Z4WR
baz
# mount
> ipfs daemon &
> ipfs mount
IPFS mounted at: /ipfs
IPNS mounted at: /ipns
> cd /ipfs/QmSh5e7S6fdcu75LAbXNZAFY2nGyZUJXyLCJDvn2zRkWyC
> ls
bar
> cat bar
baz
> cat /ipfs/QmSh5e7S6fdcu75LAbXNZAFY2nGyZUJXyLCJDvn2zRkWyC/bar
baz
> cat /ipfs/QmWLdkp93sNxGRjnFHPaYg8tCQ35NBY3XPn6KiETd3Z4WR
baz
`,
},
Options: []cmdkit.Option{
cmdkit.StringOption("ipfs-path", "f", "The path where IPFS should be mounted."),
cmdkit.StringOption("ipns-path", "n", "The path where IPNS should be mounted."),
},

//TODO: GetNode -> GetApi
//TODO: properly migrate to cmds 2.0; review
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) (err error) {
defer res.Close()

node, err := cmdenv.GetNode(env)
if err != nil {
return err
}

conf, err := cmdenv.GetConfig(env)
if err != nil {
return err
}

mountPoint := conf.Mounts.IPFS
//TODO: if mountPoint == default; platform switch; win32 = \\.\ipfs\$mountpoint
//TODO: investigate, this doesn't seem to work
//WinFSP sets up via the filesystem name, when undefined, this is the service/proc name
// i.e. \\ipfs\mountpoint => \\$procname|$fsName\\mountpoint
/*
mountPoint = `\\ipfs\ipfs\` //DBG
go fsh.Mount(mountPoint, []string{"-o uid=-1,gid=-1,pid=-1", "-o fstypename=ipfs", "--VolumePrefix=\\ipfs"})
*/

/* TODO: coalesce non-unique mountpoints, multi mount instances
f(mountRoot, functionConfig, ...roots)
config{/ipfs, /ipns, /usr/home/cooleuser/mfs} =>
go f("/", opts, ipfsRoot, ipnsRoot)
go f("/usr/home/cooluser", opts, mfsRoot)
*/

//TODO: we need to decide where to store this; we'll need some other scope for graceful destruction from `unmount`

//TODO [current]: pass something to the mount instance so that we can block on it here, right now our errors will be ignored
fsi := &mi.FUSEIPFS{APINode: node}
fsh := fuse.NewFileSystemHost(fsi)

//fsh.SetCapReaddirPlus(true) //TODO: win32 only; needs testing
fsh.SetCapCaseInsensitive(false)

//TODO: check state of daemon, if offline, wait for signal to exit; otherwise run in background
//FIXME: cgofuse has its own signal/interrupt handler; need to ctrl+c twice
go func() {
defer func() {
//TODO: breakout into platform specific panic handlers?
if r := recover(); r != nil {
if typedR, ok := r.(string); ok {
if typedR == "cgofuse: cannot find winfsp" {
err = errors.New("WinFSP(http://www.secfs.net/winfsp/) is required for mount on this platform, but it was not found")
}
err = errors.New(typedR)
return
}
err = fmt.Errorf("Mount panicked! %v", r)
}
}()

fsh.Mount(mountPoint, []string{"-o uid=-1,gid=-1,pid=-1,fstypename=IPFS"})
//fsh.Mount(mountPoint, []string{"-d", "-o uid=-1,gid=-1,pid=-1,fstypename=IPFS"})
}()
//go fsh.Mount(mountPoint, []string{"-o uid=-1,gid=-1,pid=-1", "-d"})

//TODO: switch on signal from mount call; succeed or fail
absMount, err := filepath.Abs(mountPoint)
if err != nil {
absMount = mountPoint
}
cmds.EmitOnce(res, fmt.Sprintf("%#q mounted", absMount))
return nil
},
}
74 changes: 74 additions & 0 deletions core/commands/mount/cache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package fusemount

import (
cid "gx/ipfs/QmR8BauakNcBa3RbE4nbQu76PDiJgoQgz8AJdhJuiU4TAw/go-cid"

"github.com/alexanderGugel/arc"
)

/*
type cidCache interface {
Add(*cid.Cid, fusePath)
Request(*cid.Cid) fusePath
Release(*cid.Cid)
}
*/

//TODO: ability to disable cache
type cidCache struct {
actual *arc.ARC
}

func (cc *cidCache) Add(cid cid.Cid, fp fusePath) {
/*
cc.Lock()
k := cid.String()
if _, ok := cc.activeDags[k]; !ok {
cc.activeDags[k] = &cidCachePair{fp: fp, refCount: 1}
}
cc.Unlock()
*/

/* NOTE: ok is false if already exists in cache
if ok := cc.actual.Put(cid, fp); !ok {
log.Errorf("Cache - Add failed for [%s]%s", cid, fp)
}
*/
cc.actual.Put(cid, fp)
}

/*
func (cc *cidCache) Release(cid *cid.Cid) {
cc.Lock()
defer cc.Unlock()
k := cid.String()
if _, ok := cc.activeDags[k]; !ok {
return
}
cc.activeDags[k].refCount--
if cc.activeDags[k].refCount == 0 {
delete(cc.activeDags, k)
}
}
*/
func (cc *cidCache) Request(cid cid.Cid) fusePath {
if v, ok := cc.actual.Get(cid); ok {
if _, ok = v.(fusePath); !ok {
log.Errorf("Cache - Request returned invalid data")
return nil
}
return v.(fusePath)
}
return nil
}

//TODO: size from conf?
func (cc *cidCache) Init() {
cc.actual = arc.New(100) //NOTE: arbitrary debug size
}

//TODO: for each cache (size, keys, etc) place in remove.go with notes
//size: gtihub issue to unixfs size
//keys: node doesn't send events yet
// etc.

0 comments on commit ec5978c

Please sign in to comment.