Skip to content

Commit 13353bc

Browse files
author
Manuel Valls Fernández
committed
Improve Uid & Gid support
The purpose of this PR is to allow file systems to: 1. Create inodes with the UID and GID of the calling process 2. Support chown
1 parent 659cc51 commit 13353bc

6 files changed

Lines changed: 95 additions & 18 deletions

File tree

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ before_install:
2828
# For linux: install fuse.
2929
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
3030
sudo apt-get install -qq fuse;
31+
sudo echo user_allow_other > /etc/fuse.conf;
3132
fi
3233

3334
# For macOS: update homebrew and then install osxfuse.

conversions.go

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,9 @@ func convertInMessage(
4141
inMsg *buffer.InMessage,
4242
outMsg *buffer.OutMessage,
4343
protocol fusekernel.Protocol) (o interface{}, err error) {
44-
switch inMsg.Header().Opcode {
44+
header := inMsg.Header()
45+
46+
switch header.Opcode {
4547
case fusekernel.OpLookup:
4648
buf := inMsg.ConsumeBytes(inMsg.Len())
4749
n := len(buf)
@@ -93,6 +95,14 @@ func convertInMessage(
9395
to.Mtime = &t
9496
}
9597

98+
if valid&fusekernel.SetattrUid != 0 {
99+
to.Uid = &in.Uid
100+
}
101+
102+
if valid&fusekernel.SetattrGid != 0 {
103+
to.Gid = &in.Gid
104+
}
105+
96106
case fusekernel.OpForget:
97107
type input fusekernel.ForgetIn
98108
in := (*input)(inMsg.Consume(unsafe.Sizeof(input{})))
@@ -132,6 +142,8 @@ func convertInMessage(
132142
// opcode is mkdir. But we want the correct mode to go through, so ensure
133143
// that os.ModeDir is set.
134144
Mode: convertFileMode(in.Mode) | os.ModeDir,
145+
Uid: header.Uid,
146+
Gid: header.Gid,
135147
}
136148

137149
case fusekernel.OpMknod:
@@ -153,6 +165,8 @@ func convertInMessage(
153165
Parent: fuseops.InodeID(inMsg.Header().Nodeid),
154166
Name: string(name),
155167
Mode: convertFileMode(in.Mode),
168+
Uid: header.Uid,
169+
Gid: header.Gid,
156170
}
157171

158172
case fusekernel.OpCreate:
@@ -174,6 +188,8 @@ func convertInMessage(
174188
Parent: fuseops.InodeID(inMsg.Header().Nodeid),
175189
Name: string(name),
176190
Mode: convertFileMode(in.Mode),
191+
Uid: header.Uid,
192+
Gid: header.Gid,
177193
}
178194

179195
case fusekernel.OpSymlink:
@@ -194,6 +210,8 @@ func convertInMessage(
194210
Parent: fuseops.InodeID(inMsg.Header().Nodeid),
195211
Name: string(newName),
196212
Target: string(target),
213+
Uid: header.Uid,
214+
Gid: header.Gid,
197215
}
198216

199217
case fusekernel.OpRename:

fuseops/ops.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,8 @@ type SetInodeAttributesOp struct {
150150
Mode *os.FileMode
151151
Atime *time.Time
152152
Mtime *time.Time
153+
Uid *uint32
154+
Gid *uint32
153155

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

233+
// The uid and gid of the parent process
234+
Uid uint32
235+
Gid uint32
236+
231237
// Set by the file system: information about the inode that was created.
232238
//
233239
// The lookup count for the inode is implicitly incremented. See notes on
@@ -255,6 +261,10 @@ type MkNodeOp struct {
255261
Name string
256262
Mode os.FileMode
257263

264+
// The uid and gid of the parent process
265+
Uid uint32
266+
Gid uint32
267+
258268
// Set by the file system: information about the inode that was created.
259269
//
260270
// The lookup count for the inode is implicitly incremented. See notes on
@@ -280,6 +290,10 @@ type CreateFileOp struct {
280290
Name string
281291
Mode os.FileMode
282292

293+
// The uid and gid of the parent process
294+
Uid uint32
295+
Gid uint32
296+
283297
// Set by the file system: information about the inode that was created.
284298
//
285299
// The lookup count for the inode is implicitly incremented. See notes on
@@ -306,6 +320,10 @@ type CreateSymlinkOp struct {
306320
// The name of the symlink to create.
307321
Name string
308322

323+
// The uid and gid of the parent process
324+
Uid uint32
325+
Gid uint32
326+
309327
// The target of the symlink.
310328
Target string
311329

samples/memfs/inode.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,9 @@ func (in *inode) WriteAt(p []byte, off int64) (n int, err error) {
352352
func (in *inode) SetAttributes(
353353
size *uint64,
354354
mode *os.FileMode,
355-
mtime *time.Time) {
355+
mtime *time.Time,
356+
uid *uint32,
357+
gid *uint32) {
356358
// Update the modification time.
357359
in.attrs.Mtime = time.Now()
358360

@@ -381,4 +383,14 @@ func (in *inode) SetAttributes(
381383
if mtime != nil {
382384
in.attrs.Mtime = *mtime
383385
}
386+
387+
// Change uid?
388+
if uid != nil {
389+
in.attrs.Uid = *uid
390+
}
391+
392+
// Change gid?
393+
if gid != nil {
394+
in.attrs.Gid = *gid
395+
}
384396
}

samples/memfs/memfs.go

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,6 @@ import (
3131
type memFS struct {
3232
fuseutil.NotImplementedFileSystem
3333

34-
// The UID and GID that every inode receives.
35-
uid uint32
36-
gid uint32
37-
3834
/////////////////////////
3935
// Mutable state
4036
/////////////////////////
@@ -73,8 +69,6 @@ func NewMemFS(
7369
// Set up the basic struct.
7470
fs := &memFS{
7571
inodes: make([]*inode, fuseops.RootInodeID+1),
76-
uid: uid,
77-
gid: gid,
7872
}
7973

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

252246
// Handle the request.
253-
inode.SetAttributes(op.Size, op.Mode, op.Mtime)
247+
inode.SetAttributes(op.Size, op.Mode, op.Mtime, op.Uid, op.Gid)
254248

255249
// Fill in the response.
256250
op.Attributes = inode.attrs
@@ -283,8 +277,8 @@ func (fs *memFS) MkDir(
283277
childAttrs := fuseops.InodeAttributes{
284278
Nlink: 1,
285279
Mode: op.Mode,
286-
Uid: fs.uid,
287-
Gid: fs.gid,
280+
Uid: op.Uid,
281+
Gid: op.Gid,
288282
}
289283

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

314-
op.Entry, err = fs.createFile(op.Parent, op.Name, op.Mode)
308+
op.Entry, err = fs.createFile(op.Parent, op.Name, op.Mode, op.Uid, op.Gid)
315309
return
316310
}
317311

318312
// LOCKS_REQUIRED(fs.mu)
319313
func (fs *memFS) createFile(
320314
parentID fuseops.InodeID,
321315
name string,
322-
mode os.FileMode) (entry fuseops.ChildInodeEntry, err error) {
316+
mode os.FileMode,
317+
uid uint32,
318+
gid uint32) (entry fuseops.ChildInodeEntry, err error) {
323319
// Grab the parent, which we will update shortly.
324320
parent := fs.getInodeOrDie(parentID)
325321

@@ -340,8 +336,8 @@ func (fs *memFS) createFile(
340336
Mtime: now,
341337
Ctime: now,
342338
Crtime: now,
343-
Uid: fs.uid,
344-
Gid: fs.gid,
339+
Uid: uid,
340+
Gid: gid,
345341
}
346342

347343
// Allocate a child.
@@ -368,7 +364,7 @@ func (fs *memFS) CreateFile(
368364
fs.mu.Lock()
369365
defer fs.mu.Unlock()
370366

371-
op.Entry, err = fs.createFile(op.Parent, op.Name, op.Mode)
367+
op.Entry, err = fs.createFile(op.Parent, op.Name, op.Mode, op.Uid, op.Gid)
372368
return
373369
}
374370

@@ -398,8 +394,8 @@ func (fs *memFS) CreateSymlink(
398394
Mtime: now,
399395
Ctime: now,
400396
Crtime: now,
401-
Uid: fs.uid,
402-
Gid: fs.gid,
397+
Uid: op.Uid,
398+
Gid: op.Gid,
403399
}
404400

405401
// Allocate a child.

samples/memfs/memfs_test.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"io"
2020
"io/ioutil"
2121
"os"
22+
"os/exec"
2223
"os/user"
2324
"path"
2425
"reflect"
@@ -97,6 +98,14 @@ type memFSTest struct {
9798

9899
func (t *memFSTest) SetUp(ti *TestInfo) {
99100
t.Server = memfs.NewMemFS(currentUid(), currentGid())
101+
102+
// If the OS is linux, we need to specify allow_other for
103+
// sudo to work
104+
if os.Getenv("TRAVIS_OS_NAME") == "linux" {
105+
t.SampleTest.MountConfig.Options = make(map[string]string)
106+
t.SampleTest.MountConfig.Options["allow_other"] = ""
107+
}
108+
100109
t.SampleTest.SetUp(ti)
101110
}
102111

@@ -1007,6 +1016,29 @@ func (t *MemFSTest) Chmod() {
10071016
ExpectEq(0754, fi.Mode())
10081017
}
10091018

1019+
func (t *MemFSTest) Chown() {
1020+
var err error
1021+
fileName := path.Join(t.Dir, "foo")
1022+
1023+
// Create a file.
1024+
err = ioutil.WriteFile(fileName, []byte(""), 0600)
1025+
AssertEq(nil, err)
1026+
1027+
// Chown it.
1028+
err = exec.Command("sudo", "chown", "50:51", fileName).Run()
1029+
AssertEq(nil, err)
1030+
1031+
// Stat it.
1032+
fi, err := os.Stat(fileName)
1033+
AssertEq(nil, err)
1034+
stat, ok := fi.Sys().(*syscall.Stat_t)
1035+
1036+
if ok {
1037+
ExpectEq(50, stat.Uid)
1038+
ExpectEq(51, stat.Gid)
1039+
}
1040+
}
1041+
10101042
func (t *MemFSTest) Chtimes() {
10111043
var err error
10121044
fileName := path.Join(t.Dir, "foo")

0 commit comments

Comments
 (0)