Skip to content

Commit

Permalink
Added support for mknod(2).
Browse files Browse the repository at this point in the history
For #137.
  • Loading branch information
jacobsa committed Dec 15, 2015
2 parents 0d2fd94 + cdc0e77 commit a6f9ff1
Show file tree
Hide file tree
Showing 7 changed files with 211 additions and 21 deletions.
54 changes: 49 additions & 5 deletions internal/fs/fs.go
Original file line number Diff line number Diff line change
Expand Up @@ -1056,18 +1056,49 @@ func (fs *fileSystem) MkDir(
}

// LOCKS_EXCLUDED(fs.mu)
func (fs *fileSystem) CreateFile(
func (fs *fileSystem) MkNode(
ctx context.Context,
op *fuseops.CreateFileOp) (err error) {
op *fuseops.MkNodeOp) (err error) {
// Create the child.
child, err := fs.createFile(ctx, op.Parent, op.Name, op.Mode)
if err != nil {
return
}

defer fs.unlockAndMaybeDisposeOfInode(child, &err)

// Fill out the response.
e := &op.Entry
e.Child = child.ID()
e.Attributes, e.AttributesExpiration, err = fs.getAttributes(ctx, child)

if err != nil {
err = fmt.Errorf("getAttributes: %v", err)
return
}

return
}

// Create a child of the parent with the given ID, returning the child locked
// and with its lookup count incremented.
//
// LOCKS_EXCLUDED(fs.mu)
// LOCK_FUNCTION(child)
func (fs *fileSystem) createFile(
ctx context.Context,
parentID fuseops.InodeID,
name string,
mode os.FileMode) (child inode.Inode, err error) {
// Find the parent.
fs.mu.Lock()
parent := fs.inodes[op.Parent].(inode.DirInode)
parent := fs.inodes[parentID].(inode.DirInode)
fs.mu.Unlock()

// Create an empty backing object for the child, failing if it already
// exists.
parent.Lock()
o, err := parent.CreateChildFile(ctx, op.Name)
o, err := parent.CreateChildFile(ctx, name)
parent.Unlock()

// Special case: *gcs.PreconditionError means the name already exists.
Expand All @@ -1086,12 +1117,25 @@ func (fs *fileSystem) CreateFile(
// do so, it means someone beat us to the punch with a newer generation
// (unlikely, so we're probably okay with failing here).
fs.mu.Lock()
child := fs.lookUpOrCreateInodeIfNotStale(o.Name, o)
child = fs.lookUpOrCreateInodeIfNotStale(o.Name, o)
if child == nil {
err = fmt.Errorf("Newly-created record is already stale")
return
}

return
}

// LOCKS_EXCLUDED(fs.mu)
func (fs *fileSystem) CreateFile(
ctx context.Context,
op *fuseops.CreateFileOp) (err error) {
// Create the child.
child, err := fs.createFile(ctx, op.Parent, op.Name, op.Mode)
if err != nil {
return
}

defer fs.unlockAndMaybeDisposeOfInode(child, &err)

// Allocate a handle.
Expand Down
80 changes: 80 additions & 0 deletions internal/fs/local_modifications_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,86 @@ func (t *OpenTest) IllegalNames() {
}
}

////////////////////////////////////////////////////////////////////////
// Mknod
////////////////////////////////////////////////////////////////////////

type MknodTest struct {
fsTest
}

func init() { RegisterTestSuite(&MknodTest{}) }

func (t *MknodTest) File() {
// mknod(2) only works for root on OS X.
if runtime.GOOS == "darwin" { return }

var err error
p := path.Join(t.mfs.Dir(), "foo")

// Create
err = syscall.Mknod(p, syscall.S_IFREG|0600, 0)
AssertEq(nil, err)

// Stat
fi, err := os.Stat(p)
AssertEq(nil, err)

ExpectEq(path.Base(p), fi.Name())
ExpectEq(0, fi.Size())
ExpectEq(filePerms, fi.Mode())

// Read
contents, err := ioutil.ReadFile(p)
AssertEq(nil, err)
ExpectEq("", string(contents))
}

func (t *MknodTest) Directory() {
// mknod(2) only works for root on OS X.
if runtime.GOOS == "darwin" { return }

var err error
p := path.Join(t.mfs.Dir(), "foo")

// Quoth `man 2 mknod`: "Under Linux, this call cannot be used to create
// directories."
err = syscall.Mknod(p, syscall.S_IFDIR|0700, 0)
ExpectEq(syscall.EPERM, err)
}

func (t *MknodTest) AlreadyExists() {
// mknod(2) only works for root on OS X.
if runtime.GOOS == "darwin" { return }

var err error
p := path.Join(t.mfs.Dir(), "foo")

// Create (first)
err = ioutil.WriteFile(p, []byte("taco"), 0600)
AssertEq(nil, err)

// Create (second)
err = syscall.Mknod(p, syscall.S_IFREG|0600, 0)
ExpectEq(syscall.EEXIST, err)

// Read
contents, err := ioutil.ReadFile(p)
AssertEq(nil, err)
ExpectEq("taco", string(contents))
}

func (t *MknodTest) NonExistentParent() {
// mknod(2) only works for root on OS X.
if runtime.GOOS == "darwin" { return }

var err error
p := path.Join(t.mfs.Dir(), "foo/bar")

err = syscall.Mknod(p, syscall.S_IFREG|0600, 0)
ExpectEq(syscall.ENOENT, err)
}

////////////////////////////////////////////////////////////////////////
// Modes
////////////////////////////////////////////////////////////////////////
Expand Down
28 changes: 28 additions & 0 deletions vendor/github.com/jacobsa/fuse/conversions.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

27 changes: 27 additions & 0 deletions vendor/github.com/jacobsa/fuse/fuseops/ops.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

32 changes: 16 additions & 16 deletions vendor/vendor.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,43 +9,43 @@
},
{
"path": "github.com/jacobsa/fuse",
"revision": "bc664bf39be72bcf975d71007fa767f15d3a7d7c",
"revisionTime": "2015-09-10T13:55:51+10:00"
"revision": "895b8c415580ff864f707cc0016b08ff840cd23b",
"revisionTime": "2015-12-15T10:55:29+11:00"
},
{
"path": "github.com/jacobsa/fuse/fsutil",
"revision": "bc664bf39be72bcf975d71007fa767f15d3a7d7c",
"revisionTime": "2015-09-10T13:55:51+10:00"
"revision": "895b8c415580ff864f707cc0016b08ff840cd23b",
"revisionTime": "2015-12-15T10:55:29+11:00"
},
{
"path": "github.com/jacobsa/fuse/fuseops",
"revision": "bc664bf39be72bcf975d71007fa767f15d3a7d7c",
"revisionTime": "2015-09-10T13:55:51+10:00"
"revision": "895b8c415580ff864f707cc0016b08ff840cd23b",
"revisionTime": "2015-12-15T10:55:29+11:00"
},
{
"path": "github.com/jacobsa/fuse/fusetesting",
"revision": "bc664bf39be72bcf975d71007fa767f15d3a7d7c",
"revisionTime": "2015-09-10T13:55:51+10:00"
"revision": "895b8c415580ff864f707cc0016b08ff840cd23b",
"revisionTime": "2015-12-15T10:55:29+11:00"
},
{
"path": "github.com/jacobsa/fuse/fuseutil",
"revision": "bc664bf39be72bcf975d71007fa767f15d3a7d7c",
"revisionTime": "2015-09-10T13:55:51+10:00"
"revision": "895b8c415580ff864f707cc0016b08ff840cd23b",
"revisionTime": "2015-12-15T10:55:29+11:00"
},
{
"path": "github.com/jacobsa/fuse/internal/buffer",
"revision": "bc664bf39be72bcf975d71007fa767f15d3a7d7c",
"revisionTime": "2015-09-10T13:55:51+10:00"
"revision": "895b8c415580ff864f707cc0016b08ff840cd23b",
"revisionTime": "2015-12-15T10:55:29+11:00"
},
{
"path": "github.com/jacobsa/fuse/internal/freelist",
"revision": "bc664bf39be72bcf975d71007fa767f15d3a7d7c",
"revisionTime": "2015-09-10T13:55:51+10:00"
"revision": "895b8c415580ff864f707cc0016b08ff840cd23b",
"revisionTime": "2015-12-15T10:55:29+11:00"
},
{
"path": "github.com/jacobsa/fuse/internal/fusekernel",
"revision": "bc664bf39be72bcf975d71007fa767f15d3a7d7c",
"revisionTime": "2015-09-10T13:55:51+10:00"
"revision": "895b8c415580ff864f707cc0016b08ff840cd23b",
"revisionTime": "2015-12-15T10:55:29+11:00"
},
{
"path": "github.com/jacobsa/gcloud/gcs",
Expand Down

0 comments on commit a6f9ff1

Please sign in to comment.