Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve Uid & Gid support #40

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ before_install:
# For linux: install fuse.
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
sudo apt-get install -qq fuse;
sudo echo user_allow_other > /etc/fuse.conf;
fi

# For macOS: update homebrew and then install osxfuse.
Expand Down
20 changes: 19 additions & 1 deletion conversions.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ func convertInMessage(
inMsg *buffer.InMessage,
outMsg *buffer.OutMessage,
protocol fusekernel.Protocol) (o interface{}, err error) {
switch inMsg.Header().Opcode {
header := inMsg.Header()

switch header.Opcode {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: use switch header := inMsg.Header(); header.Opcode to scope the header variable to the switch block only (smaller scopes are generally preferable)

case fusekernel.OpLookup:
buf := inMsg.ConsumeBytes(inMsg.Len())
n := len(buf)
Expand Down Expand Up @@ -93,6 +95,14 @@ func convertInMessage(
to.Mtime = &t
}

if valid&fusekernel.SetattrUid != 0 {
to.Uid = &in.Uid
}

if valid&fusekernel.SetattrGid != 0 {
to.Gid = &in.Gid
}

case fusekernel.OpForget:
type input fusekernel.ForgetIn
in := (*input)(inMsg.Consume(unsafe.Sizeof(input{})))
Expand Down Expand Up @@ -132,6 +142,8 @@ func convertInMessage(
// opcode is mkdir. But we want the correct mode to go through, so ensure
// that os.ModeDir is set.
Mode: convertFileMode(in.Mode) | os.ModeDir,
Uid: header.Uid,
Gid: header.Gid,
}

case fusekernel.OpMknod:
Expand All @@ -153,6 +165,8 @@ func convertInMessage(
Parent: fuseops.InodeID(inMsg.Header().Nodeid),
Name: string(name),
Mode: convertFileMode(in.Mode),
Uid: header.Uid,
Gid: header.Gid,
}

case fusekernel.OpCreate:
Expand All @@ -174,6 +188,8 @@ func convertInMessage(
Parent: fuseops.InodeID(inMsg.Header().Nodeid),
Name: string(name),
Mode: convertFileMode(in.Mode),
Uid: header.Uid,
Gid: header.Gid,
}

case fusekernel.OpSymlink:
Expand All @@ -194,6 +210,8 @@ func convertInMessage(
Parent: fuseops.InodeID(inMsg.Header().Nodeid),
Name: string(newName),
Target: string(target),
Uid: header.Uid,
Gid: header.Gid,
}

case fusekernel.OpRename:
Expand Down
18 changes: 18 additions & 0 deletions fuseops/ops.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,8 @@ type SetInodeAttributesOp struct {
Mode *os.FileMode
Atime *time.Time
Mtime *time.Time
Uid *uint32
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason why you’re adding Uid/Gid only to some operations, but not to all? Isn’t the uid/gid field set by the kernel for all requests?

Gid *uint32

// Set by the file system: the new attributes for the inode, and the time at
// which they should expire. See notes on
Expand Down Expand Up @@ -228,6 +230,10 @@ type MkDirOp struct {
Name string
Mode os.FileMode

// The uid and gid of the parent process
Uid uint32
Gid uint32

// Set by the file system: information about the inode that was created.
//
// The lookup count for the inode is implicitly incremented. See notes on
Expand Down Expand Up @@ -255,6 +261,10 @@ type MkNodeOp struct {
Name string
Mode os.FileMode

// The uid and gid of the parent process
Uid uint32
Gid uint32

// Set by the file system: information about the inode that was created.
//
// The lookup count for the inode is implicitly incremented. See notes on
Expand All @@ -280,6 +290,10 @@ type CreateFileOp struct {
Name string
Mode os.FileMode

// The uid and gid of the parent process
Uid uint32
Gid uint32

// Set by the file system: information about the inode that was created.
//
// The lookup count for the inode is implicitly incremented. See notes on
Expand All @@ -306,6 +320,10 @@ type CreateSymlinkOp struct {
// The name of the symlink to create.
Name string

// The uid and gid of the parent process
Uid uint32
Gid uint32

// The target of the symlink.
Target string

Expand Down
14 changes: 13 additions & 1 deletion samples/memfs/inode.go
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,9 @@ func (in *inode) WriteAt(p []byte, off int64) (n int, err error) {
func (in *inode) SetAttributes(
size *uint64,
mode *os.FileMode,
mtime *time.Time) {
mtime *time.Time,
uid *uint32,
gid *uint32) {
// Update the modification time.
in.attrs.Mtime = time.Now()

Expand Down Expand Up @@ -381,4 +383,14 @@ func (in *inode) SetAttributes(
if mtime != nil {
in.attrs.Mtime = *mtime
}

// Change uid?
if uid != nil {
in.attrs.Uid = *uid
}

// Change gid?
if gid != nil {
in.attrs.Gid = *gid
}
}
28 changes: 12 additions & 16 deletions samples/memfs/memfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,6 @@ import (
type memFS struct {
fuseutil.NotImplementedFileSystem

// The UID and GID that every inode receives.
uid uint32
gid uint32

/////////////////////////
// Mutable state
/////////////////////////
Expand Down Expand Up @@ -73,8 +69,6 @@ func NewMemFS(
// Set up the basic struct.
fs := &memFS{
inodes: make([]*inode, fuseops.RootInodeID+1),
uid: uid,
gid: gid,
}

// Set up the root inode.
Expand Down Expand Up @@ -250,7 +244,7 @@ func (fs *memFS) SetInodeAttributes(
inode := fs.getInodeOrDie(op.Inode)

// Handle the request.
inode.SetAttributes(op.Size, op.Mode, op.Mtime)
inode.SetAttributes(op.Size, op.Mode, op.Mtime, op.Uid, op.Gid)

// Fill in the response.
op.Attributes = inode.attrs
Expand Down Expand Up @@ -283,8 +277,8 @@ func (fs *memFS) MkDir(
childAttrs := fuseops.InodeAttributes{
Nlink: 1,
Mode: op.Mode,
Uid: fs.uid,
Gid: fs.gid,
Uid: op.Uid,
Gid: op.Gid,
}

// Allocate a child.
Expand All @@ -311,15 +305,17 @@ func (fs *memFS) MkNode(
fs.mu.Lock()
defer fs.mu.Unlock()

op.Entry, err = fs.createFile(op.Parent, op.Name, op.Mode)
op.Entry, err = fs.createFile(op.Parent, op.Name, op.Mode, op.Uid, op.Gid)
return
}

// LOCKS_REQUIRED(fs.mu)
func (fs *memFS) createFile(
parentID fuseops.InodeID,
name string,
mode os.FileMode) (entry fuseops.ChildInodeEntry, err error) {
mode os.FileMode,
uid uint32,
gid uint32) (entry fuseops.ChildInodeEntry, err error) {
// Grab the parent, which we will update shortly.
parent := fs.getInodeOrDie(parentID)

Expand All @@ -340,8 +336,8 @@ func (fs *memFS) createFile(
Mtime: now,
Ctime: now,
Crtime: now,
Uid: fs.uid,
Gid: fs.gid,
Uid: uid,
Gid: gid,
}

// Allocate a child.
Expand All @@ -368,7 +364,7 @@ func (fs *memFS) CreateFile(
fs.mu.Lock()
defer fs.mu.Unlock()

op.Entry, err = fs.createFile(op.Parent, op.Name, op.Mode)
op.Entry, err = fs.createFile(op.Parent, op.Name, op.Mode, op.Uid, op.Gid)
return
}

Expand Down Expand Up @@ -398,8 +394,8 @@ func (fs *memFS) CreateSymlink(
Mtime: now,
Ctime: now,
Crtime: now,
Uid: fs.uid,
Gid: fs.gid,
Uid: op.Uid,
Gid: op.Gid,
}

// Allocate a child.
Expand Down
32 changes: 32 additions & 0 deletions samples/memfs/memfs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"io"
"io/ioutil"
"os"
"os/exec"
"os/user"
"path"
"reflect"
Expand Down Expand Up @@ -97,6 +98,14 @@ type memFSTest struct {

func (t *memFSTest) SetUp(ti *TestInfo) {
t.Server = memfs.NewMemFS(currentUid(), currentGid())

// If the OS is linux, we need to specify allow_other for
// sudo to work
if os.Getenv("TRAVIS_OS_NAME") == "linux" {
t.SampleTest.MountConfig.Options = make(map[string]string)
t.SampleTest.MountConfig.Options["allow_other"] = ""
}

t.SampleTest.SetUp(ti)
}

Expand Down Expand Up @@ -1007,6 +1016,29 @@ func (t *MemFSTest) Chmod() {
ExpectEq(0754, fi.Mode())
}

func (t *MemFSTest) Chown() {
var err error
fileName := path.Join(t.Dir, "foo")

// Create a file.
err = ioutil.WriteFile(fileName, []byte(""), 0600)
AssertEq(nil, err)

// Chown it.
err = exec.Command("sudo", "chown", "50:51", fileName).Run()
AssertEq(nil, err)

// Stat it.
fi, err := os.Stat(fileName)
AssertEq(nil, err)
stat, ok := fi.Sys().(*syscall.Stat_t)

if ok {
ExpectEq(50, stat.Uid)
ExpectEq(51, stat.Gid)
}
}

func (t *MemFSTest) Chtimes() {
var err error
fileName := path.Join(t.Dir, "foo")
Expand Down