Skip to content

Commit

Permalink
introduce concept of filedescriptors to mfs, adjust fuse code to use …
Browse files Browse the repository at this point in the history
…them

License: MIT
Signed-off-by: Jeromy <jeromyj@gmail.com>
  • Loading branch information
whyrusleeping committed Feb 4, 2016
1 parent 4f8ac94 commit 49e72d5
Show file tree
Hide file tree
Showing 10 changed files with 575 additions and 253 deletions.
33 changes: 22 additions & 11 deletions core/commands/files/files.go
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,14 @@ Examples:
return
}

rfd, err := fi.Open(mfs.OpenReadOnly, false)
if err != nil {
res.SetError(err, cmds.ErrNormal)
return
}

defer rfd.Close()

offset, _, err := req.Option("offset").Int()
if err != nil {
res.SetError(err, cmds.ErrNormal)
Expand All @@ -378,7 +386,7 @@ Examples:
return
}

filen, err := fi.Size()
filen, err := rfd.Size()
if err != nil {
res.SetError(err, cmds.ErrNormal)
return
Expand All @@ -389,12 +397,13 @@ Examples:
return
}

_, err = fi.Seek(int64(offset), os.SEEK_SET)
_, err = rfd.Seek(int64(offset), os.SEEK_SET)
if err != nil {
res.SetError(err, cmds.ErrNormal)
return
}
var r io.Reader = &contextReaderWrapper{R: fi, ctx: req.Context()}

var r io.Reader = &contextReaderWrapper{R: rfd, ctx: req.Context()}
count, found, err := req.Option("count").Int()
if err != nil {
res.SetError(err, cmds.ErrNormal)
Expand All @@ -405,7 +414,7 @@ Examples:
res.SetError(fmt.Errorf("cannot specify negative 'count'"), cmds.ErrNormal)
return
}
r = io.LimitReader(fi, int64(count))
r = io.LimitReader(r, int64(count))
}

res.SetOutput(r)
Expand Down Expand Up @@ -540,14 +549,16 @@ Warning:
return
}

if flush {
defer fi.Close()
} else {
defer fi.Sync()
wfd, err := fi.Open(mfs.OpenWriteOnly, flush)
if err != nil {
res.SetError(err, cmds.ErrNormal)
return
}

defer wfd.Close()

if trunc {
if err := fi.Truncate(0); err != nil {
if err := wfd.Truncate(0); err != nil {
res.SetError(err, cmds.ErrNormal)
return
}
Expand All @@ -563,7 +574,7 @@ Warning:
return
}

_, err = fi.Seek(int64(offset), os.SEEK_SET)
_, err = wfd.Seek(int64(offset), os.SEEK_SET)
if err != nil {
log.Error("seekfail: ", err)
res.SetError(err, cmds.ErrNormal)
Expand All @@ -581,7 +592,7 @@ Warning:
r = io.LimitReader(r, int64(count))
}

n, err := io.Copy(fi, input)
n, err := io.Copy(wfd, input)
if err != nil {
res.SetError(err, cmds.ErrNormal)
return
Expand Down
20 changes: 17 additions & 3 deletions fuse/ipns/ipns_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,15 +89,26 @@ func checkExists(t *testing.T, path string) {
}
}

func closeMount(mnt *fstest.Mount) {
func closeMount(mnt *mountWrap) {
if err := recover(); err != nil {
log.Error("Recovered panic")
log.Error(err)
}
mnt.Close()
}

func setupIpnsTest(t *testing.T, node *core.IpfsNode) (*core.IpfsNode, *fstest.Mount) {
type mountWrap struct {
*fstest.Mount
Fs *FileSystem
}

func (m *mountWrap) Close() error {
m.Fs.Destroy()
m.Mount.Close()
return nil
}

func setupIpnsTest(t *testing.T, node *core.IpfsNode) (*core.IpfsNode, *mountWrap) {
maybeSkipFuseTests(t)

var err error
Expand Down Expand Up @@ -130,7 +141,10 @@ func setupIpnsTest(t *testing.T, node *core.IpfsNode) (*core.IpfsNode, *fstest.M
t.Fatal(err)
}

return node, mnt
return node, &mountWrap{
Mount: mnt,
Fs: fs,
}
}

func TestIpnsLocalLink(t *testing.T) {
Expand Down
92 changes: 73 additions & 19 deletions fuse/ipns/ipns_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ import (
ft "github.com/ipfs/go-ipfs/unixfs"
)

func init() {
if os.Getenv("IPFS_FUSE_DEBUG") != "" {
fuse.Debug = func(msg interface{}) {
fmt.Println(msg)
}
}
}

var log = logging.Logger("fuse/ipns")

// FileSystem is the readwrite IPNS Fuse Filesystem.
Expand Down Expand Up @@ -102,7 +110,7 @@ func loadRoot(ctx context.Context, rt *keyRoot, ipfs *core.IpfsNode, name string
case *mfs.Directory:
return &Directory{dir: val}, nil
case *mfs.File:
return &File{fi: val}, nil
return &FileNode{fi: val}, nil
default:
return nil, errors.New("unrecognized type")
}
Expand Down Expand Up @@ -177,7 +185,7 @@ func (s *Root) Lookup(ctx context.Context, name string) (fs.Node, error) {
switch nd := nd.(type) {
case *Directory:
return nd, nil
case *File:
case *FileNode:
return nd, nil
default:
return nil, fuse.EIO
Expand Down Expand Up @@ -248,15 +256,15 @@ func (r *Root) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
// Directory is wrapper over an mfs directory to satisfy the fuse fs interface
type Directory struct {
dir *mfs.Directory
}

fs.NodeRef
type FileNode struct {
fi *mfs.File
}

// File is wrapper over an mfs file to satisfy the fuse fs interface
type File struct {
fi *mfs.File

fs.NodeRef
fi mfs.FileDescriptor
}

// Attr returns the attributes of a given node.
Expand All @@ -269,7 +277,7 @@ func (d *Directory) Attr(ctx context.Context, a *fuse.Attr) error {
}

// Attr returns the attributes of a given node.
func (fi *File) Attr(ctx context.Context, a *fuse.Attr) error {
func (fi *FileNode) Attr(ctx context.Context, a *fuse.Attr) error {
log.Debug("File Attr")
size, err := fi.fi.Size()
if err != nil {
Expand All @@ -295,7 +303,7 @@ func (s *Directory) Lookup(ctx context.Context, name string) (fs.Node, error) {
case *mfs.Directory:
return &Directory{dir: child}, nil
case *mfs.File:
return &File{fi: child}, nil
return &FileNode{fi: child}, nil
default:
// NB: if this happens, we do not want to continue, unpredictable behaviour
// may occur.
Expand Down Expand Up @@ -365,7 +373,7 @@ func (fi *File) Write(ctx context.Context, req *fuse.WriteRequest, resp *fuse.Wr
func (fi *File) Flush(ctx context.Context, req *fuse.FlushRequest) error {
errs := make(chan error, 1)
go func() {
errs <- fi.fi.Close()
errs <- fi.fi.Flush()
}()
select {
case err := <-errs:
Expand Down Expand Up @@ -393,7 +401,7 @@ func (fi *File) Setattr(ctx context.Context, req *fuse.SetattrRequest, resp *fus

// Fsync flushes the content in the file to disk, but does not
// update the dag tree internally
func (fi *File) Fsync(ctx context.Context, req *fuse.FsyncRequest) error {
func (fi *FileNode) Fsync(ctx context.Context, req *fuse.FsyncRequest) error {
errs := make(chan error, 1)
go func() {
errs <- fi.fi.Sync()
Expand Down Expand Up @@ -422,25 +430,49 @@ func (dir *Directory) Mkdir(ctx context.Context, req *fuse.MkdirRequest) (fs.Nod
return &Directory{dir: child}, nil
}

func (fi *File) Open(ctx context.Context, req *fuse.OpenRequest, resp *fuse.OpenResponse) (fs.Handle, error) {
func (fi *FileNode) Open(ctx context.Context, req *fuse.OpenRequest, resp *fuse.OpenResponse) (fs.Handle, error) {
var mfsflag int
switch {
case req.Flags.IsReadOnly():
mfsflag = mfs.OpenReadOnly
case req.Flags.IsWriteOnly():
mfsflag = mfs.OpenWriteOnly
case req.Flags.IsReadWrite():
mfsflag = mfs.OpenReadWrite
default:
return nil, errors.New("unsupported flag type")
}

fd, err := fi.fi.Open(mfsflag, true)
if err != nil {
return nil, err
}

if req.Flags&fuse.OpenTruncate != 0 {
if req.Flags.IsReadOnly() {
log.Error("tried to open a readonly file with truncate")
return nil, fuse.ENOTSUP
}
log.Info("Need to truncate file!")
err := fi.fi.Truncate(0)
err := fd.Truncate(0)
if err != nil {
return nil, err
}
} else if req.Flags&fuse.OpenAppend != 0 {
log.Info("Need to append to file!")
if req.Flags.IsReadOnly() {
log.Error("tried to open a readonly file with append")
return nil, fuse.ENOTSUP
}

// seek(0) essentially resets the file object, this is required for appends to work
// properly
_, err := fi.fi.Seek(0, os.SEEK_SET)
_, err := fd.Seek(0, os.SEEK_END)
if err != nil {
log.Error("seek reset failed: ", err)
return nil, err
}
}
return fi, nil

return &File{fi: fd}, nil
}

func (fi *File) Release(ctx context.Context, req *fuse.ReleaseRequest) error {
Expand All @@ -465,8 +497,26 @@ func (dir *Directory) Create(ctx context.Context, req *fuse.CreateRequest, resp
return nil, nil, errors.New("child creation failed")
}

nodechild := &File{fi: fi}
return nodechild, nodechild, nil
nodechild := &FileNode{fi: fi}

var openflag int
switch {
case req.Flags.IsReadOnly():
openflag = mfs.OpenReadOnly
case req.Flags.IsWriteOnly():
openflag = mfs.OpenWriteOnly
case req.Flags.IsReadWrite():
openflag = mfs.OpenReadWrite
default:
return nil, nil, errors.New("unsupported open mode")
}

fd, err := fi.Open(openflag, true)
if err != nil {
return nil, nil, err
}

return nodechild, &File{fi: fd}, nil
}

func (dir *Directory) Remove(ctx context.Context, req *fuse.RemoveRequest) error {
Expand Down Expand Up @@ -500,7 +550,7 @@ func (dir *Directory) Rename(ctx context.Context, req *fuse.RenameRequest, newDi
if err != nil {
return err
}
case *File:
case *FileNode:
log.Error("Cannot move node into a file!")
return fuse.EPERM
default:
Expand Down Expand Up @@ -543,9 +593,13 @@ type ipnsFile interface {
fs.HandleReader
fs.HandleWriter
fs.HandleReleaser
}

type ipnsFileNode interface {
fs.Node
fs.NodeFsyncer
fs.NodeOpener
}

var _ ipnsFileNode = (*FileNode)(nil)
var _ ipnsFile = (*File)(nil)
12 changes: 2 additions & 10 deletions mfs/dir.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,8 +183,8 @@ type NodeListing struct {
}

func (d *Directory) ListNames() []string {
d.Lock()
defer d.Unlock()
d.lock.Lock()
defer d.lock.Unlock()

names := make(map[string]struct{})
for n, _ := range d.childDirs {
Expand Down Expand Up @@ -391,11 +391,3 @@ func (d *Directory) GetNode() (*dag.Node, error) {

return d.node.Copy(), nil
}

func (d *Directory) Lock() {
d.lock.Lock()
}

func (d *Directory) Unlock() {
d.lock.Unlock()
}
Loading

0 comments on commit 49e72d5

Please sign in to comment.