From 226fec2ce90233da445603322f6efaee639bdcb7 Mon Sep 17 00:00:00 2001 From: Mei Gui <71293871+xinmeigui-db@users.noreply.github.com> Date: Tue, 26 Jul 2022 00:34:00 -0700 Subject: [PATCH] Pass OpenFlags for OpenFileOp followups (#129) --- conversions.go | 3 +-- fuseops/ops.go | 2 +- samples/memfs/inode.go | 7 ++++++- samples/memfs/memfs.go | 41 +++++++++++++++++++++++++++++-------- samples/memfs/memfs_test.go | 29 ++++++++++++++++++++------ 5 files changed, 63 insertions(+), 19 deletions(-) diff --git a/conversions.go b/conversions.go index ddb57d5..fbcc7bb 100644 --- a/conversions.go +++ b/conversions.go @@ -299,11 +299,10 @@ func convertInMessage( if in == nil { return nil, errors.New("Corrupt OpOpen") } - openFlags := fusekernel.OpenFlags(in.Flags) o = &fuseops.OpenFileOp{ Inode: fuseops.InodeID(inMsg.Header().Nodeid), - OpenFlags: &openFlags, + OpenFlags: fusekernel.OpenFlags(in.Flags), OpContext: fuseops.OpContext{Pid: inMsg.Header().Pid}, } diff --git a/fuseops/ops.go b/fuseops/ops.go index 0f51b25..e92db76 100644 --- a/fuseops/ops.go +++ b/fuseops/ops.go @@ -648,7 +648,7 @@ type OpenFileOp struct { // advance, for example, because contents are generated on the fly. UseDirectIO bool - OpenFlags *fusekernel.OpenFlags + OpenFlags fusekernel.OpenFlags OpContext OpContext } diff --git a/samples/memfs/inode.go b/samples/memfs/inode.go index 170b5f2..10ed54f 100644 --- a/samples/memfs/inode.go +++ b/samples/memfs/inode.go @@ -33,6 +33,10 @@ type inode struct { // Mutable state ///////////////////////// + // Name of the inode, only contains relative path. + // For example, if the full path for an inode is /foo/bar/f1, its name is f1. + name string + // The current attributes of this inode. // // INVARIANT: attrs.Mode &^ (os.ModePerm|os.ModeDir|os.ModeSymlink) == 0 @@ -73,7 +77,7 @@ type inode struct { // Create a new inode with the supplied attributes, which need not contain // time-related information (the inode object will take care of that). -func newInode(attrs fuseops.InodeAttributes) *inode { +func newInode(attrs fuseops.InodeAttributes, name string) *inode { // Update time info. now := time.Now() attrs.Mtime = now @@ -81,6 +85,7 @@ func newInode(attrs fuseops.InodeAttributes) *inode { // Create the object. return &inode{ + name: name, attrs: attrs, xattrs: make(map[string][]byte), } diff --git a/samples/memfs/memfs.go b/samples/memfs/memfs.go index 3fb0206..3f22206 100644 --- a/samples/memfs/memfs.go +++ b/samples/memfs/memfs.go @@ -16,6 +16,7 @@ package memfs import ( "context" + "encoding/binary" "fmt" "io" "os" @@ -29,6 +30,11 @@ import ( "golang.org/x/sys/unix" ) +const ( + FileOpenFlagsXattrName = "fileOpenFlagsXattr" + CheckFileOpenFlagsFileName = "checkFileOpenFlags" +) + type memFS struct { fuseutil.NotImplementedFileSystem @@ -85,7 +91,7 @@ func NewMemFS( Gid: gid, } - fs.inodes[fuseops.RootInodeID] = newInode(rootAttrs) + fs.inodes[fuseops.RootInodeID] = newInode(rootAttrs, "") // Set up invariant checking. fs.mu = syncutil.NewInvariantMutex(fs.checkInvariants) @@ -157,9 +163,9 @@ func (fs *memFS) getInodeOrDie(id fuseops.InodeID) *inode { // // LOCKS_REQUIRED(fs.mu) func (fs *memFS) allocateInode( - attrs fuseops.InodeAttributes) (id fuseops.InodeID, inode *inode) { + attrs fuseops.InodeAttributes, name string) (id fuseops.InodeID, inode *inode) { // Create the inode. - inode = newInode(attrs) + inode = newInode(attrs, name) // Re-use a free ID if possible. Otherwise mint a new one. numFree := len(fs.freeInodes) @@ -310,7 +316,7 @@ func (fs *memFS) MkDir( } // Allocate a child. - childID, child := fs.allocateInode(childAttrs) + childID, child := fs.allocateInode(childAttrs, op.Name) // Add an entry in the parent. parent.AddChild(childID, op.Name, fuseutil.DT_Directory) @@ -371,7 +377,7 @@ func (fs *memFS) createFile( } // Allocate a child. - childID, child := fs.allocateInode(childAttrs) + childID, child := fs.allocateInode(childAttrs, name) // Add an entry in the parent. parent.AddChild(childID, name, fuseutil.DT_File) @@ -438,7 +444,7 @@ func (fs *memFS) CreateSymlink( } // Allocate a child. - childID, child := fs.allocateInode(childAttrs) + childID, child := fs.allocateInode(childAttrs, op.Name) // Set up its target. child.target = op.Target @@ -661,9 +667,6 @@ func (fs *memFS) OpenFile( // OpenFileOp should have a valid pid in context. return fuse.EINVAL } - if op.OpenFlags == nil { - return fuse.EINVAL - } fs.mu.Lock() defer fs.mu.Unlock() @@ -677,6 +680,21 @@ func (fs *memFS) OpenFile( panic("Found non-file.") } + if inode.name == CheckFileOpenFlagsFileName { + // For testing purpose only. + // Set attribute (name=fileOpenFlagsXattr, value=OpenFlags) to test whether + // we set OpenFlags correctly. The value is checked in test with getXattr. + value := make([]byte, 4) + binary.LittleEndian.PutUint32(value, uint32(op.OpenFlags)) + err := fs.setXattrHelper(inode, &fuseops.SetXattrOp{ + Name: FileOpenFlagsXattrName, + Value: value, + }) + if err != nil { + panic("unable to set fileOpenFlagsXattr") + } + } + return nil } @@ -832,6 +850,11 @@ func (fs *memFS) SetXattr(ctx context.Context, defer fs.mu.Unlock() inode := fs.getInodeOrDie(op.Inode) + return fs.setXattrHelper(inode, op) +} + +// Required to hold fs.mu +func (fs *memFS) setXattrHelper(inode *inode, op *fuseops.SetXattrOp) error { _, ok := inode.xattrs[op.Name] switch op.Flags { diff --git a/samples/memfs/memfs_test.go b/samples/memfs/memfs_test.go index aa1dc47..74e272a 100644 --- a/samples/memfs/memfs_test.go +++ b/samples/memfs/memfs_test.go @@ -16,6 +16,7 @@ package memfs_test import ( "bytes" + "encoding/binary" "io" "io/ioutil" "os" @@ -31,6 +32,7 @@ import ( fallocate "github.com/detailyang/go-fallocate" "github.com/jacobsa/fuse" "github.com/jacobsa/fuse/fusetesting" + "github.com/jacobsa/fuse/internal/fusekernel" "github.com/jacobsa/fuse/samples" "github.com/jacobsa/fuse/samples/memfs" . "github.com/jacobsa/oglematchers" @@ -88,6 +90,15 @@ func applyUmask(m os.FileMode) os.FileMode { return m &^ os.FileMode(umask) } +func (t *MemFSTest) checkOpenFlagsXattr( + fileName string, expectedOpenFlags fusekernel.OpenFlags) { + dest := make([]byte, 4) + _, err := unix.Getxattr(fileName, memfs.FileOpenFlagsXattrName, dest) + AssertEq(nil, err) + openFlags := binary.LittleEndian.Uint32(dest) + AssertEq(openFlags, uint32(expectedOpenFlags)) +} + //////////////////////////////////////////////////////////////////////// // Boilerplate //////////////////////////////////////////////////////////////////////// @@ -292,7 +303,7 @@ func (t *MemFSTest) CreateNewFile_InRoot() { var stat *syscall.Stat_t // Write a file. - fileName := path.Join(t.Dir, "foo") + fileName := path.Join(t.Dir, memfs.CheckFileOpenFlagsFileName) const contents = "Hello\x00world" createTime := time.Now() @@ -304,7 +315,7 @@ func (t *MemFSTest) CreateNewFile_InRoot() { stat = fi.Sys().(*syscall.Stat_t) AssertEq(nil, err) - ExpectEq("foo", fi.Name()) + ExpectEq(memfs.CheckFileOpenFlagsFileName, fi.Name()) ExpectEq(len(contents), fi.Size()) ExpectEq(applyUmask(0400), fi.Mode()) ExpectThat(fi, fusetesting.MtimeIsWithin(createTime, timeSlop)) @@ -321,6 +332,7 @@ func (t *MemFSTest) CreateNewFile_InRoot() { slice, err := ioutil.ReadFile(fileName) AssertEq(nil, err) ExpectEq(contents, string(slice)) + t.checkOpenFlagsXattr(fileName, fusekernel.OpenReadOnly) } func (t *MemFSTest) CreateNewFile_InSubDir() { @@ -372,7 +384,7 @@ func (t *MemFSTest) ModifyExistingFile_InRoot() { var stat *syscall.Stat_t // Write a file. - fileName := path.Join(t.Dir, "foo") + fileName := path.Join(t.Dir, memfs.CheckFileOpenFlagsFileName) createTime := time.Now() err = ioutil.WriteFile(fileName, []byte("Hello, world!"), 0600) @@ -382,6 +394,7 @@ func (t *MemFSTest) ModifyExistingFile_InRoot() { f, err := os.OpenFile(fileName, os.O_WRONLY, 0400) t.ToClose = append(t.ToClose, f) AssertEq(nil, err) + t.checkOpenFlagsXattr(fileName, fusekernel.OpenWriteOnly) modifyTime := time.Now() n, err = f.WriteAt([]byte("H"), 0) @@ -393,7 +406,7 @@ func (t *MemFSTest) ModifyExistingFile_InRoot() { stat = fi.Sys().(*syscall.Stat_t) AssertEq(nil, err) - ExpectEq("foo", fi.Name()) + ExpectEq(memfs.CheckFileOpenFlagsFileName, fi.Name()) ExpectEq(len("Hello, world!"), fi.Size()) ExpectEq(applyUmask(0600), fi.Mode()) ExpectThat(fi, fusetesting.MtimeIsWithin(modifyTime, timeSlop)) @@ -410,6 +423,7 @@ func (t *MemFSTest) ModifyExistingFile_InRoot() { slice, err := ioutil.ReadFile(fileName) AssertEq(nil, err) ExpectEq("Hello, world!", string(slice)) + t.checkOpenFlagsXattr(fileName, fusekernel.OpenReadOnly) } func (t *MemFSTest) ModifyExistingFile_InSubDir() { @@ -832,7 +846,7 @@ func (t *MemFSTest) AppendMode() { buf := make([]byte, 1024) // Create a file with some contents. - fileName := path.Join(t.Dir, "foo") + fileName := path.Join(t.Dir, memfs.CheckFileOpenFlagsFileName) err = ioutil.WriteFile(fileName, []byte("Jello, "), 0600) AssertEq(nil, err) @@ -840,6 +854,7 @@ func (t *MemFSTest) AppendMode() { f, err := os.OpenFile(fileName, os.O_RDWR|os.O_APPEND, 0600) t.ToClose = append(t.ToClose, f) AssertEq(nil, err) + t.checkOpenFlagsXattr(fileName, fusekernel.OpenReadWrite) // Seek to somewhere silly and then write. off, err = f.Seek(2, 0) @@ -907,7 +922,7 @@ func (t *MemFSTest) ReadsPastEndOfFile() { func (t *MemFSTest) Truncate_Smaller() { var err error - fileName := path.Join(t.Dir, "foo") + fileName := path.Join(t.Dir, memfs.CheckFileOpenFlagsFileName) // Create a file. err = ioutil.WriteFile(fileName, []byte("taco"), 0600) @@ -917,6 +932,7 @@ func (t *MemFSTest) Truncate_Smaller() { f, err := os.OpenFile(fileName, os.O_RDWR, 0) t.ToClose = append(t.ToClose, f) AssertEq(nil, err) + t.checkOpenFlagsXattr(fileName, fusekernel.OpenReadWrite) // Truncate it. err = f.Truncate(2) @@ -931,6 +947,7 @@ func (t *MemFSTest) Truncate_Smaller() { contents, err := ioutil.ReadFile(fileName) AssertEq(nil, err) ExpectEq("ta", string(contents)) + t.checkOpenFlagsXattr(fileName, fusekernel.OpenReadOnly) } func (t *MemFSTest) Truncate_SameSize() {