Commit ae2e1d5c authored by OneOfOne's avatar OneOfOne Committed by Han-Wen Nienhuys

Flock implementation with test.

Fixes #134
parent 51b6e576
...@@ -123,6 +123,8 @@ type RawFileSystem interface { ...@@ -123,6 +123,8 @@ type RawFileSystem interface {
Open(input *OpenIn, out *OpenOut) (status Status) Open(input *OpenIn, out *OpenOut) (status Status)
Read(input *ReadIn, buf []byte) (ReadResult, Status) Read(input *ReadIn, buf []byte) (ReadResult, Status)
Flock(input *FlockIn, flags int) (code Status)
Release(input *ReleaseIn) Release(input *ReleaseIn)
Write(input *WriteIn, data []byte) (written uint32, code Status) Write(input *WriteIn, data []byte) (written uint32, code Status)
Flush(input *FlushIn) Status Flush(input *FlushIn) Status
......
...@@ -117,6 +117,10 @@ func (fs *defaultRawFileSystem) Read(input *ReadIn, buf []byte) (ReadResult, Sta ...@@ -117,6 +117,10 @@ func (fs *defaultRawFileSystem) Read(input *ReadIn, buf []byte) (ReadResult, Sta
return nil, ENOSYS return nil, ENOSYS
} }
func (fs *defaultRawFileSystem) Flock(input *FlockIn, flags int) Status {
return ENOSYS
}
func (fs *defaultRawFileSystem) Release(input *ReleaseIn) { func (fs *defaultRawFileSystem) Release(input *ReleaseIn) {
} }
......
...@@ -159,6 +159,11 @@ func (fs *lockingRawFileSystem) Read(input *ReadIn, buf []byte) (ReadResult, Sta ...@@ -159,6 +159,11 @@ func (fs *lockingRawFileSystem) Read(input *ReadIn, buf []byte) (ReadResult, Sta
return fs.RawFS.Read(input, buf) return fs.RawFS.Read(input, buf)
} }
func (fs *lockingRawFileSystem) Flock(input *FlockIn, flags int) Status {
defer fs.locked()()
return fs.RawFS.Flock(input, flags)
}
func (fs *lockingRawFileSystem) Write(input *WriteIn, data []byte) (written uint32, code Status) { func (fs *lockingRawFileSystem) Write(input *WriteIn, data []byte) (written uint32, code Status) {
defer fs.locked()() defer fs.locked()()
return fs.RawFS.Write(input, data) return fs.RawFS.Write(input, data)
......
...@@ -130,6 +130,8 @@ type File interface { ...@@ -130,6 +130,8 @@ type File interface {
Read(dest []byte, off int64) (fuse.ReadResult, fuse.Status) Read(dest []byte, off int64) (fuse.ReadResult, fuse.Status)
Write(data []byte, off int64) (written uint32, code fuse.Status) Write(data []byte, off int64) (written uint32, code fuse.Status)
Flock(flags int) fuse.Status
// Flush is called for close() call on a file descriptor. In // Flush is called for close() call on a file descriptor. In
// case of duplicated descriptor, it may be called more than // case of duplicated descriptor, it may be called more than
// once for a file. // once for a file.
......
...@@ -37,6 +37,7 @@ func (f *defaultFile) Write(data []byte, off int64) (uint32, fuse.Status) { ...@@ -37,6 +37,7 @@ func (f *defaultFile) Write(data []byte, off int64) (uint32, fuse.Status) {
return 0, fuse.ENOSYS return 0, fuse.ENOSYS
} }
func (f *defaultFile) Flock(flags int) fuse.Status { return fuse.ENOSYS }
func (f *defaultFile) Flush() fuse.Status { func (f *defaultFile) Flush() fuse.Status {
return fuse.OK return fuse.OK
} }
......
...@@ -167,6 +167,14 @@ func (f *loopbackFile) Fsync(flags int) (code fuse.Status) { ...@@ -167,6 +167,14 @@ func (f *loopbackFile) Fsync(flags int) (code fuse.Status) {
return r return r
} }
func (f *loopbackFile) Flock(flags int) fuse.Status {
f.lock.Lock()
r := fuse.ToStatus(syscall.Flock(int(f.File.Fd()), flags))
f.lock.Unlock()
return r
}
func (f *loopbackFile) Truncate(size uint64) fuse.Status { func (f *loopbackFile) Truncate(size uint64) fuse.Status {
f.lock.Lock() f.lock.Lock()
r := fuse.ToStatus(syscall.Ftruncate(int(f.File.Fd()), int64(size))) r := fuse.ToStatus(syscall.Ftruncate(int(f.File.Fd()), int64(size)))
......
...@@ -455,6 +455,17 @@ func (c *rawBridge) Read(input *fuse.ReadIn, buf []byte) (fuse.ReadResult, fuse. ...@@ -455,6 +455,17 @@ func (c *rawBridge) Read(input *fuse.ReadIn, buf []byte) (fuse.ReadResult, fuse.
return node.Node().Read(f, buf, int64(input.Offset), &input.Context) return node.Node().Read(f, buf, int64(input.Offset), &input.Context)
} }
func (c *rawBridge) Flock(input *fuse.FlockIn, flags int) fuse.Status {
node := c.toInode(input.NodeId)
opened := node.mount.getOpenedFile(input.Fh)
if opened != nil {
return opened.WithFlags.File.Flock(flags)
}
return fuse.EBADF
}
func (c *rawBridge) StatFs(header *fuse.InHeader, out *fuse.StatfsOut) fuse.Status { func (c *rawBridge) StatFs(header *fuse.InHeader, out *fuse.StatfsOut) fuse.Status {
node := c.toInode(header.NodeId) node := c.toInode(header.NodeId)
s := node.Node().StatFs() s := node.Node().StatFs()
......
...@@ -54,6 +54,12 @@ func (f *lockingFile) Flush() fuse.Status { ...@@ -54,6 +54,12 @@ func (f *lockingFile) Flush() fuse.Status {
return f.file.Flush() return f.file.Flush()
} }
func (f *lockingFile) Flock(flags int) fuse.Status {
f.mu.Lock()
defer f.mu.Unlock()
return f.file.Flock(flags)
}
func (f *lockingFile) Release() { func (f *lockingFile) Release() {
f.mu.Lock() f.mu.Lock()
defer f.mu.Unlock() defer f.mu.Unlock()
......
// Copyright 2016 the Go-FUSE Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build linux
package test
import (
"bytes"
"os"
"os/exec"
"syscall"
"testing"
)
func TestFlock(t *testing.T) {
cmd, err := exec.LookPath("flock")
if err != nil {
t.Skip("flock command not found.")
}
tc := NewTestCase(t)
defer tc.Cleanup()
contents := []byte{1, 2, 3}
tc.WriteFile(tc.origFile, []byte(contents), 0700)
f, err := os.OpenFile(tc.mountFile, os.O_WRONLY, 0)
if err != nil {
t.Fatalf("OpenFile(%q): %v", tc.mountFile, err)
}
defer f.Close()
if err = syscall.Flock(int(f.Fd()), syscall.LOCK_EX); err != nil {
t.Errorf("Flock returned: %v", err)
return
}
if out, err := runExternalFlock(cmd, tc.mountFile); !bytes.Contains(out, []byte("failed to get lock")) {
t.Errorf("runExternalFlock(%q): %s (%v)", tc.mountFile, out, err)
}
}
func runExternalFlock(flockPath, fname string) ([]byte, error) {
f, err := os.OpenFile(fname, os.O_WRONLY, 0)
if err != nil {
return nil, err
}
defer f.Close()
cmd := exec.Command(flockPath, "--verbose", "--exclusive", "--nonblock", "3")
cmd.Env = append(cmd.Env, "LC_ALL=C") // in case the user's shell language is different
cmd.ExtraFiles = []*os.File{f}
return cmd.CombinedOutput()
}
...@@ -510,6 +510,7 @@ func TestAccess(t *testing.T) { ...@@ -510,6 +510,7 @@ func TestAccess(t *testing.T) {
contents := []byte{1, 2, 3} contents := []byte{1, 2, 3}
tc.WriteFile(tc.origFile, []byte(contents), 0700) tc.WriteFile(tc.origFile, []byte(contents), 0700)
if err := os.Chmod(tc.origFile, 0); err != nil { if err := os.Chmod(tc.origFile, 0); err != nil {
t.Fatalf("Chmod failed: %v", err) t.Fatalf("Chmod failed: %v", err)
} }
......
...@@ -26,6 +26,9 @@ const ( ...@@ -26,6 +26,9 @@ const (
// EBUSY Device or resource busy // EBUSY Device or resource busy
EBUSY = Status(syscall.EBUSY) EBUSY = Status(syscall.EBUSY)
// EAGAIN Resource temporarily unavailable
EAGAIN = Status(syscall.EAGAIN)
// EINVAL Invalid argument // EINVAL Invalid argument
EINVAL = Status(syscall.EINVAL) EINVAL = Status(syscall.EINVAL)
...@@ -462,3 +465,8 @@ type FallocateIn struct { ...@@ -462,3 +465,8 @@ type FallocateIn struct {
Mode uint32 Mode uint32
Padding uint32 Padding uint32
} }
type FlockIn struct {
InHeader
Fh uint64
}
...@@ -244,6 +244,15 @@ func (fs *wrappingFS) Read(input *ReadIn, buf []byte) (ReadResult, Status) { ...@@ -244,6 +244,15 @@ func (fs *wrappingFS) Read(input *ReadIn, buf []byte) (ReadResult, Status) {
return nil, ENOSYS return nil, ENOSYS
} }
func (fs *wrappingFS) Flock(input *FlockIn, flags int) Status {
if s, ok := fs.fs.(interface {
Flock(input *FlockIn, flags int) Status
}); ok {
return s.Flock(input, flags)
}
return ENOSYS
}
func (fs *wrappingFS) Release(input *ReleaseIn) { func (fs *wrappingFS) Release(input *ReleaseIn) {
if s, ok := fs.fs.(interface { if s, ok := fs.fs.(interface {
Release(input *ReleaseIn) Release(input *ReleaseIn)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment