Skip to content

Commit

Permalink
Rework Writable interface to only do full file writes
Browse files Browse the repository at this point in the history
Implement the new Writable interface (defined to mirror the Readable
interface). Implement Write on a local file interface for testing.

Also adds fuse/file tests.

Supports puppetlabs-toy-chest#620.

Signed-off-by: Michael Smith <[email protected]>
  • Loading branch information
MikaelSmith committed Dec 18, 2019
1 parent b4e3ed6 commit 130e9df
Show file tree
Hide file tree
Showing 13 changed files with 806 additions and 118 deletions.
5 changes: 5 additions & 0 deletions api/fs/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,9 @@ func (f *file) Schema() *plugin.EntrySchema {
return plugin.NewEntrySchema(f, "file")
}

func (f *file) Write(ctx context.Context, p []byte) error {
return ioutil.WriteFile(f.path, p, 0640)
}

var _ = plugin.Readable(&file{})
var _ = plugin.Writable(&file{})
58 changes: 9 additions & 49 deletions fuse/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,18 +55,16 @@ func getIDs() (uint32, uint32) {
var uid, gid = getIDs()

type fuseNode struct {
ftype string
parent *dir
entry plugin.Entry
entryCreationTime time.Time
ftype string
parent *dir
entry plugin.Entry
}

func newFuseNode(ftype string, parent *dir, entry plugin.Entry) *fuseNode {
return &fuseNode{
ftype: ftype,
parent: parent,
entry: entry,
entryCreationTime: time.Now(),
func newFuseNode(ftype string, parent *dir, entry plugin.Entry) fuseNode {
return fuseNode{
ftype: ftype,
parent: parent,
entry: entry,
}
}

Expand All @@ -75,7 +73,7 @@ func (f *fuseNode) String() string {
}

// Applies attributes where non-default, and sets defaults otherwise.
func (f *fuseNode) applyAttr(a *fuse.Attr, attr *plugin.EntryAttributes, defaultMode os.FileMode) {
func applyAttr(a *fuse.Attr, attr plugin.EntryAttributes, defaultMode os.FileMode) {
// Setting a.Valid to 1 second avoids frequent Attr calls.
a.Valid = 1 * time.Second

Expand Down Expand Up @@ -143,44 +141,6 @@ func (f *fuseNode) refind(ctx context.Context) (plugin.Entry, error) {
return plugin.FindEntry(ctx, parent, segments)
}

func (f *fuseNode) Attr(ctx context.Context, a *fuse.Attr) error {
// Attr is not a particularly interesting call and happens a lot. Log it to debug like other
// activity, but leave it out of activity because it introduces history entries for lots of
// miscellaneous shell activity.
log.Debugf("FUSE: Attr %v", f)

// FUSE caches nodes for a long time, meaning there's a chance that
// f's attributes are outdated. 'refind' requests the entry from its
// parent to ensure it has updated attributes.
updatedEntry, err := f.refind(ctx)
if err != nil {
activity.Warnf(ctx, "FUSE: Attr errored %v, %v", f, err)
return err
}
attr := plugin.Attributes(updatedEntry)
// NOTE: We could set f.entry to updatedEntry, but doing so would require
// a separate mutex which may hinder performance. Since updating f.entry
// is not strictly necessary for the other FUSE operations, we choose to
// leave it alone.

var mode os.FileMode
if plugin.ListAction().IsSupportedOn(updatedEntry) {
mode = os.ModeDir | 0550
} else {
if plugin.WriteAction().IsSupportedOn(updatedEntry) {
mode |= 0220
}
if plugin.ReadAction().IsSupportedOn(updatedEntry) ||
plugin.StreamAction().IsSupportedOn(updatedEntry) {
mode |= 0440
}
}

f.applyAttr(a, &attr, mode)
log.Debugf("FUSE: Attr finished %v", f)
return nil
}

// ServeFuseFS starts serving a fuse filesystem that lists the registered plugins.
// It returns three values:
// 1. A channel to initiate the shutdown (stopCh).
Expand Down
29 changes: 28 additions & 1 deletion fuse/dir.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package fuse

import (
"context"
"os"

"bazil.org/fuse"
"bazil.org/fuse/fs"
Expand All @@ -13,7 +14,7 @@ import (
// ==== FUSE Directory Interface ====

type dir struct {
*fuseNode
fuseNode
}

var _ fs.Node = (*dir)(nil)
Expand Down Expand Up @@ -94,3 +95,29 @@ func (d *dir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
activity.Record(ctx, "FUSE: Listed in %v: %+v", d, res)
return res, nil
}

func (d *dir) Attr(ctx context.Context, a *fuse.Attr) error {
// FUSE caches nodes for a long time, meaning there's a chance that
// f's attributes are outdated. 'refind' requests the entry from its
// parent to ensure it has updated attributes.
entry, err := d.refind(ctx)
if err != nil {
activity.Warnf(ctx, "FUSE: Attr errored %v, %v", d, err)
return err
}
// NOTE: We could set f.entry to entry, but doing so would require
// a separate mutex which may hinder performance. Since updating f.entry
// is not strictly necessary for the other FUSE operations, we choose to
// leave it alone.

applyAttr(a, plugin.Attributes(entry), os.ModeDir|0550)
// Attr is not a particularly interesting call and happens a lot. Log it to debug like other
// activity, but leave it out of activity because it introduces history entries for lots of
// miscellaneous shell activity.
if d.parent == nil {
log.Tracef("FUSE: Attr %v", d)
} else {
log.Debugf("FUSE: Attr %v: %+v", d, *a)
}
return nil
}
Loading

0 comments on commit 130e9df

Please sign in to comment.