diff --git a/Makefile b/Makefile index 231c8442f..98712baf6 100644 --- a/Makefile +++ b/Makefile @@ -16,6 +16,9 @@ install: build: cd cmd/ipfs && go build -i +nofuse: + cd cmd/ipfs && go install -tags nofuse + ############################################################## # tests targets diff --git a/core/commands/mount_nofuse.go b/core/commands/mount_nofuse.go new file mode 100644 index 000000000..60c2b0101 --- /dev/null +++ b/core/commands/mount_nofuse.go @@ -0,0 +1,28 @@ +// +build (linux darwin freebsd) and nofuse + +package commands + +import ( + "errors" + + cmds "github.com/jbenet/go-ipfs/commands" + "github.com/jbenet/go-ipfs/core" +) + +var MountCmd = &cmds.Command{ + Helptext: cmds.HelpText{ + Tagline: "Mounts IPFS to the filesystem (disabled)", + ShortDescription: ` +This version of ipfs is compiled without fuse support, which is required +for mounting. If you'd like to be able to mount, please use a version of +ipfs compiled with fuse. + +For the latest instructions, please check the project's repository: + http://github.com/jbenet/go-ipfs +`, + }, +} + +func Mount(node *core.IpfsNode, fsdir, nsdir string) error { + return errors.New("not compiled in") +} diff --git a/core/commands/mount_unix.go b/core/commands/mount_unix.go index 5db9f8150..987cde5c4 100644 --- a/core/commands/mount_unix.go +++ b/core/commands/mount_unix.go @@ -1,4 +1,4 @@ -// +build linux darwin freebsd +// +build (linux darwin freebsd) and !nofuse package commands diff --git a/fuse/ipns/common.go b/fuse/ipns/common.go new file mode 100644 index 000000000..45c391d75 --- /dev/null +++ b/fuse/ipns/common.go @@ -0,0 +1,37 @@ +package ipns + +import ( + "github.com/jbenet/go-ipfs/core" + mdag "github.com/jbenet/go-ipfs/merkledag" + nsys "github.com/jbenet/go-ipfs/namesys" + ci "github.com/jbenet/go-ipfs/p2p/crypto" + ft "github.com/jbenet/go-ipfs/unixfs" +) + +// InitializeKeyspace sets the ipns record for the given key to +// point to an empty directory. +func InitializeKeyspace(n *core.IpfsNode, key ci.PrivKey) error { + emptyDir := &mdag.Node{Data: ft.FolderPBData()} + nodek, err := n.DAG.Add(emptyDir) + if err != nil { + return err + } + + err = n.Pinning.Pin(emptyDir, false) + if err != nil { + return err + } + + err = n.Pinning.Flush() + if err != nil { + return err + } + + pub := nsys.NewRoutingPublisher(n.Routing) + err = pub.Publish(n.Context(), key, nodek) + if err != nil { + return err + } + + return nil +} diff --git a/fuse/ipns/ipns_test.go b/fuse/ipns/ipns_test.go index 189846669..83f175b37 100644 --- a/fuse/ipns/ipns_test.go +++ b/fuse/ipns/ipns_test.go @@ -1,15 +1,17 @@ +// +build !nofuse + package ipns import ( "bytes" "crypto/rand" - context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" "io/ioutil" "os" "testing" "time" fstest "github.com/jbenet/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs/fstestutil" + context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" core "github.com/jbenet/go-ipfs/core" u "github.com/jbenet/go-ipfs/util" diff --git a/fuse/ipns/ipns_unix.go b/fuse/ipns/ipns_unix.go index edb126f6c..645b9ce27 100644 --- a/fuse/ipns/ipns_unix.go +++ b/fuse/ipns/ipns_unix.go @@ -1,3 +1,5 @@ +// +build !nofuse + // package fuse/ipns implements a fuse filesystem that interfaces // with ipns, the naming system for ipfs. package ipns @@ -18,7 +20,6 @@ import ( core "github.com/jbenet/go-ipfs/core" chunk "github.com/jbenet/go-ipfs/importer/chunk" mdag "github.com/jbenet/go-ipfs/merkledag" - nsys "github.com/jbenet/go-ipfs/namesys" ci "github.com/jbenet/go-ipfs/p2p/crypto" path "github.com/jbenet/go-ipfs/path" ft "github.com/jbenet/go-ipfs/unixfs" @@ -37,34 +38,6 @@ var ( longRepublishTimeout = time.Millisecond * 500 ) -// InitializeKeyspace sets the ipns record for the given key to -// point to an empty directory. -func InitializeKeyspace(n *core.IpfsNode, key ci.PrivKey) error { - emptyDir := &mdag.Node{Data: ft.FolderPBData()} - nodek, err := n.DAG.Add(emptyDir) - if err != nil { - return err - } - - err = n.Pinning.Pin(emptyDir, false) - if err != nil { - return err - } - - err = n.Pinning.Flush() - if err != nil { - return err - } - - pub := nsys.NewRoutingPublisher(n.Routing) - err = pub.Publish(n.Context(), key, nodek) - if err != nil { - return err - } - - return nil -} - // FileSystem is the readwrite IPNS Fuse Filesystem. type FileSystem struct { Ipfs *core.IpfsNode diff --git a/fuse/ipns/link_unix.go b/fuse/ipns/link_unix.go index 2b3bd0065..5353296d8 100644 --- a/fuse/ipns/link_unix.go +++ b/fuse/ipns/link_unix.go @@ -1,3 +1,5 @@ +// +build !nofuse + package ipns import ( diff --git a/fuse/ipns/mount_unix.go b/fuse/ipns/mount_unix.go index ea3e499a4..37eb8aa10 100644 --- a/fuse/ipns/mount_unix.go +++ b/fuse/ipns/mount_unix.go @@ -1,4 +1,4 @@ -// +build linux darwin freebsd +// +build (linux darwin freebsd) and !nofuse package ipns diff --git a/fuse/ipns/repub_unix.go b/fuse/ipns/repub_unix.go index 4e807578d..9e3d7ac5b 100644 --- a/fuse/ipns/repub_unix.go +++ b/fuse/ipns/repub_unix.go @@ -1,3 +1,5 @@ +// +build !nofuse + package ipns import "time" diff --git a/fuse/mount/fuse.go b/fuse/mount/fuse.go new file mode 100644 index 000000000..e63ac8c44 --- /dev/null +++ b/fuse/mount/fuse.go @@ -0,0 +1,121 @@ +// +build !nofuse + +package mount + +import ( + "fmt" + "time" + + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/bazil.org/fuse" + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs" + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-ctxgroup" +) + +// mount implements go-ipfs/fuse/mount +type mount struct { + mpoint string + filesys fs.FS + fuseConn *fuse.Conn + // closeErr error + + cg ctxgroup.ContextGroup +} + +// Mount mounts a fuse fs.FS at a given location, and returns a Mount instance. +// parent is a ContextGroup to bind the mount's ContextGroup to. +func NewMount(p ctxgroup.ContextGroup, fsys fs.FS, mountpoint string) (Mount, error) { + conn, err := fuse.Mount(mountpoint) + if err != nil { + return nil, err + } + + m := &mount{ + mpoint: mountpoint, + fuseConn: conn, + filesys: fsys, + cg: ctxgroup.WithParent(p), // link it to parent. + } + m.cg.SetTeardown(m.unmount) + + // launch the mounting process. + if err := m.mount(); err != nil { + m.Unmount() // just in case. + return nil, err + } + + return m, nil +} + +func (m *mount) mount() error { + log.Infof("Mounting %s", m.MountPoint()) + + errs := make(chan error, 1) + go func() { + err := fs.Serve(m.fuseConn, m.filesys) + log.Debugf("Mounting %s -- fs.Serve returned (%s)", err) + errs <- err + close(errs) + }() + + // wait for the mount process to be done, or timed out. + select { + case <-time.After(MountTimeout): + return fmt.Errorf("Mounting %s timed out.", m.MountPoint()) + case err := <-errs: + return err + case <-m.fuseConn.Ready: + } + + // check if the mount process has an error to report + if err := m.fuseConn.MountError; err != nil { + return err + } + + log.Infof("Mounted %s", m.MountPoint()) + return nil +} + +// umount is called exactly once to unmount this service. +// note that closing the connection will not always unmount +// properly. If that happens, we bring out the big guns +// (mount.ForceUnmountManyTimes, exec unmount). +func (m *mount) unmount() error { + log.Infof("Unmounting %s", m.MountPoint()) + + // try unmounting with fuse lib + err := fuse.Unmount(m.MountPoint()) + if err == nil { + return nil + } + log.Debug("fuse unmount err: %s", err) + + // try closing the fuseConn + err = m.fuseConn.Close() + if err == nil { + return nil + } + if err != nil { + log.Debug("fuse conn error: %s", err) + } + + // try mount.ForceUnmountManyTimes + if err := ForceUnmountManyTimes(m, 10); err != nil { + return err + } + + log.Infof("Seemingly unmounted %s", m.MountPoint()) + return nil +} + +func (m *mount) CtxGroup() ctxgroup.ContextGroup { + return m.cg +} + +func (m *mount) MountPoint() string { + return m.mpoint +} + +func (m *mount) Unmount() error { + // call ContextCloser Close(), which calls unmount() exactly once. + return m.cg.Close() +} diff --git a/fuse/mount/mount.go b/fuse/mount/mount.go index 9e73a000f..a114d180b 100644 --- a/fuse/mount/mount.go +++ b/fuse/mount/mount.go @@ -7,8 +7,6 @@ import ( "runtime" "time" - fuse "github.com/jbenet/go-ipfs/Godeps/_workspace/src/bazil.org/fuse" - fs "github.com/jbenet/go-ipfs/Godeps/_workspace/src/bazil.org/fuse/fs" ctxgroup "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-ctxgroup" u "github.com/jbenet/go-ipfs/util" @@ -31,115 +29,6 @@ type Mount interface { CtxGroup() ctxgroup.ContextGroup } -// mount implements go-ipfs/fuse/mount -type mount struct { - mpoint string - filesys fs.FS - fuseConn *fuse.Conn - // closeErr error - - cg ctxgroup.ContextGroup -} - -// Mount mounts a fuse fs.FS at a given location, and returns a Mount instance. -// parent is a ContextGroup to bind the mount's ContextGroup to. -func NewMount(p ctxgroup.ContextGroup, fsys fs.FS, mountpoint string) (Mount, error) { - conn, err := fuse.Mount(mountpoint) - if err != nil { - return nil, err - } - - m := &mount{ - mpoint: mountpoint, - fuseConn: conn, - filesys: fsys, - cg: ctxgroup.WithParent(p), // link it to parent. - } - m.cg.SetTeardown(m.unmount) - - // launch the mounting process. - if err := m.mount(); err != nil { - m.Unmount() // just in case. - return nil, err - } - - return m, nil -} - -func (m *mount) mount() error { - log.Infof("Mounting %s", m.MountPoint()) - - errs := make(chan error, 1) - go func() { - err := fs.Serve(m.fuseConn, m.filesys) - log.Debugf("Mounting %s -- fs.Serve returned (%s)", err) - errs <- err - close(errs) - }() - - // wait for the mount process to be done, or timed out. - select { - case <-time.After(MountTimeout): - return fmt.Errorf("Mounting %s timed out.", m.MountPoint()) - case err := <-errs: - return err - case <-m.fuseConn.Ready: - } - - // check if the mount process has an error to report - if err := m.fuseConn.MountError; err != nil { - return err - } - - log.Infof("Mounted %s", m.MountPoint()) - return nil -} - -// umount is called exactly once to unmount this service. -// note that closing the connection will not always unmount -// properly. If that happens, we bring out the big guns -// (mount.ForceUnmountManyTimes, exec unmount). -func (m *mount) unmount() error { - log.Infof("Unmounting %s", m.MountPoint()) - - // try unmounting with fuse lib - err := fuse.Unmount(m.MountPoint()) - if err == nil { - return nil - } - log.Debug("fuse unmount err: %s", err) - - // try closing the fuseConn - err = m.fuseConn.Close() - if err == nil { - return nil - } - if err != nil { - log.Debug("fuse conn error: %s", err) - } - - // try mount.ForceUnmountManyTimes - if err := ForceUnmountManyTimes(m, 10); err != nil { - return err - } - - log.Infof("Seemingly unmounted %s", m.MountPoint()) - return nil -} - -func (m *mount) CtxGroup() ctxgroup.ContextGroup { - return m.cg -} - -func (m *mount) MountPoint() string { - return m.mpoint -} - -func (m *mount) Unmount() error { - // call ContextCloser Close(), which calls unmount() exactly once. - return m.cg.Close() -} - // ForceUnmount attempts to forcibly unmount a given mount. // It does so by calling diskutil or fusermount directly. func ForceUnmount(m Mount) error { diff --git a/fuse/readonly/ipfs_test.go b/fuse/readonly/ipfs_test.go index ebdfac56f..9816b59c2 100644 --- a/fuse/readonly/ipfs_test.go +++ b/fuse/readonly/ipfs_test.go @@ -1,3 +1,5 @@ +// +build !nofuse + package readonly import ( diff --git a/fuse/readonly/mount_unix.go b/fuse/readonly/mount_unix.go index d81d51b9c..54e2ae47a 100644 --- a/fuse/readonly/mount_unix.go +++ b/fuse/readonly/mount_unix.go @@ -1,4 +1,4 @@ -// +build linux darwin freebsd +// +build (linux darwin freebsd) and !nofuse package readonly diff --git a/fuse/readonly/readonly_unix.go b/fuse/readonly/readonly_unix.go index ed4b80f5d..159dd0718 100644 --- a/fuse/readonly/readonly_unix.go +++ b/fuse/readonly/readonly_unix.go @@ -1,4 +1,4 @@ -// +build linux darwin freebsd +// +build (linux darwin freebsd) and !nofuse // package fuse/readonly implements a fuse filesystem to access files // stored inside of ipfs.