Skip to content

Commit

Permalink
fuse,meta: support GETFLAGS/SETFLAGS ioctl
Browse files Browse the repository at this point in the history
  • Loading branch information
qingyunha committed Aug 23, 2022
1 parent e1c8d6a commit 2830ebc
Show file tree
Hide file tree
Showing 11 changed files with 371 additions and 9 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ require (

replace github.com/minio/minio v0.0.0-20210206053228-97fe57bba92c => github.com/juicedata/minio v0.0.0-20220613143934-cee0571a1b03

replace github.com/hanwen/go-fuse/v2 v2.1.1-0.20210611132105-24a1dfe6b4f8 => github.com/juicedata/go-fuse/v2 v2.1.1-0.20220720062817-183cb227b353
replace github.com/hanwen/go-fuse/v2 v2.1.1-0.20210611132105-24a1dfe6b4f8 => github.com/juicedata/go-fuse/v2 v2.1.1-0.20220822092405-ece777deb343

replace github.com/dgrijalva/jwt-go v3.2.0+incompatible => github.com/golang-jwt/jwt v3.2.1+incompatible

Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -598,8 +598,8 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/juicedata/go-fuse/v2 v2.1.1-0.20220720062817-183cb227b353 h1:cIwY+HZQiRQAYoCItVNCkpFDyPahgZzJeNM3rMgZSOE=
github.com/juicedata/go-fuse/v2 v2.1.1-0.20220720062817-183cb227b353/go.mod h1:oRyA5eK+pvJyv5otpO/DgccS8y/RvYMaO00GgRLGryc=
github.com/juicedata/go-fuse/v2 v2.1.1-0.20220822092405-ece777deb343 h1:fbMz7gSlX5eYwuWNB3Z1+dK2q2Ekg5tw6uSYYTOdZrw=
github.com/juicedata/go-fuse/v2 v2.1.1-0.20220822092405-ece777deb343/go.mod h1:oRyA5eK+pvJyv5otpO/DgccS8y/RvYMaO00GgRLGryc=
github.com/juicedata/godaemon v0.0.0-20210629045518-3da5144a127d h1:kpQMvNZJKGY3PTt7OSoahYc4nM0HY67SvK0YyS0GLwA=
github.com/juicedata/godaemon v0.0.0-20210629045518-3da5144a127d/go.mod h1:dlxKkLh3qAIPtgr2U/RVzsZJDuXA1ffg+Njikfmhvgw=
github.com/juicedata/minio v0.0.0-20220613143934-cee0571a1b03 h1:+0jiEkr6qE5Zm2+LilAv5pV/+V+V1XZ5KUv0pmXZHhQ=
Expand Down
7 changes: 7 additions & 0 deletions pkg/fuse/fuse.go
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,13 @@ func (fs *fileSystem) StatFs(cancel <-chan struct{}, in *fuse.InHeader, out *fus
return 0
}

func (fs *fileSystem) Ioctl(cancel <-chan struct{}, in *fuse.IoctlIn, out *fuse.IoctlOut, bufIn, bufOut []byte) (status fuse.Status) {
ctx := newContext(cancel, &in.InHeader)
defer releaseContext(ctx)
out.Result = int32(fs.v.Ioctl(ctx, Ino(in.NodeId), in.Cmd, in.Arg, bufIn, bufOut))
return 0
}

// Serve starts a server to serve requests from FUSE.
func Serve(v *vfs.VFS, options string, xattrs bool) error {
if err := syscall.Setpriority(syscall.PRIO_PROCESS, os.Getpid(), -19); err != nil {
Expand Down
13 changes: 13 additions & 0 deletions pkg/meta/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -834,6 +834,19 @@ func (m *baseMeta) Open(ctx Context, inode Ino, flags uint32, attr *Attr) syscal
if attr != nil && !attr.Full {
err = m.GetAttr(ctx, inode, attr)
}
if attr.Flags&FlagImmutable != 0 {
if flags&(syscall.O_WRONLY|syscall.O_RDWR) != 0 {
return syscall.EPERM
}
}
if attr.Flags&FlagAppend != 0 {
if (flags&(syscall.O_WRONLY|syscall.O_RDWR)) != 0 && (flags&syscall.O_APPEND) == 0 {
return syscall.EPERM
}
if flags&syscall.O_TRUNC != 0 {
return syscall.EPERM
}
}
if err == 0 {
m.of.Open(inode, attr)
}
Expand Down
158 changes: 158 additions & 0 deletions pkg/meta/base_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ func testMeta(t *testing.T, m Meta) {
testCopyFileRange(t, m)
testCloseSession(t, m)
testConcurrentDir(t, m)
testAttrFlags(t, m)
base := m.getBase()
base.conf.OpenCache = time.Second
base.of.expire = time.Second
Expand Down Expand Up @@ -1426,3 +1427,160 @@ func testConcurrentDir(t *testing.T, m Meta) {
}
g.Wait()
}

func testAttrFlags(t *testing.T, m Meta) {
ctx := Background
var attr = &Attr{}
var inode Ino
if st := m.Create(ctx, 1, "f", 0644, 022, 0, &inode, nil); st != 0 {
t.Fatalf("create f: %s", st)
}
attr.Flags = FlagAppend
if st := m.SetAttr(ctx, inode, SetAttrFlag, 0, attr); st != 0 {
t.Fatalf("setattr f: %s", st)
}
if st := m.Open(ctx, inode, syscall.O_WRONLY, attr); st != syscall.EPERM {
t.Fatalf("open f: %s", st)
}
if st := m.Open(ctx, inode, syscall.O_WRONLY|syscall.O_APPEND, attr); st != 0 {
t.Fatalf("open f: %s", st)
}
attr.Flags = FlagAppend | FlagImmutable
if st := m.SetAttr(ctx, inode, SetAttrFlag, 0, attr); st != 0 {
t.Fatalf("setattr f: %s", st)
}
if st := m.Open(ctx, inode, syscall.O_WRONLY, attr); st != syscall.EPERM {
t.Fatalf("open f: %s", st)
}
if st := m.Open(ctx, inode, syscall.O_WRONLY|syscall.O_APPEND, attr); st != syscall.EPERM {
t.Fatalf("open f: %s", st)
}

var d Ino
if st := m.Mkdir(ctx, 1, "d", 0640, 022, 0, &d, attr); st != 0 {
t.Fatalf("mkdir d: %s", st)
}
attr.Flags = FlagAppend
if st := m.SetAttr(ctx, d, SetAttrFlag, 0, attr); st != 0 {
t.Fatalf("setattr d: %s", st)
}
if st := m.Create(ctx, d, "f", 0644, 022, 0, &inode, nil); st != 0 {
t.Fatalf("create f: %s", st)
}
if st := m.Unlink(ctx, d, "f"); st != syscall.EPERM {
t.Fatalf("unlink f: %s", st)
}
attr.Flags = FlagAppend | FlagImmutable
if st := m.SetAttr(ctx, d, SetAttrFlag, 0, attr); st != 0 {
t.Fatalf("setattr d: %s", st)
}
if st := m.Create(ctx, d, "f2", 0644, 022, 0, &inode, nil); st != syscall.EPERM {
t.Fatalf("create f2: %s", st)
}

var Immutable Ino
if st := m.Mkdir(ctx, 1, "ImmutFile", 0640, 022, 0, &Immutable, attr); st != 0 {
t.Fatalf("mkdir d: %s", st)
}
attr.Flags = FlagImmutable
if st := m.SetAttr(ctx, Immutable, SetAttrFlag, 0, attr); st != 0 {
t.Fatalf("setattr d: %s", st)
}
if st := m.Create(ctx, Immutable, "f2", 0644, 022, 0, &inode, nil); st != syscall.EPERM {
t.Fatalf("create f2: %s", st)
}

var src1, dst1, mfile Ino
attr.Flags = 0
if st := m.Mkdir(ctx, 1, "src1", 0640, 022, 0, &src1, attr); st != 0 {
t.Fatalf("mkdir src1: %s", st)
}
if st := m.Create(ctx, src1, "mfile", 0644, 022, 0, &mfile, nil); st != 0 {
t.Fatalf("create mfile: %s", st)
}
if st := m.Mkdir(ctx, 1, "dst1", 0640, 022, 0, &dst1, attr); st != 0 {
t.Fatalf("mkdir dst1: %s", st)
}

attr.Flags = FlagAppend
if st := m.SetAttr(ctx, src1, SetAttrFlag, 0, attr); st != 0 {
t.Fatalf("setattr d: %s", st)
}
if st := m.Rename(ctx, src1, "mfile", dst1, "mfile", 0, &mfile, attr); st != syscall.EPERM {
t.Fatalf("rename d: %s", st)
}

attr.Flags = FlagImmutable
if st := m.SetAttr(ctx, src1, SetAttrFlag, 0, attr); st != 0 {
t.Fatalf("setattr d: %s", st)
}
if st := m.Rename(ctx, src1, "mfile", dst1, "mfile", 0, &mfile, attr); st != syscall.EPERM {
t.Fatalf("rename d: %s", st)
}

if st := m.SetAttr(ctx, dst1, SetAttrFlag, 0, attr); st != 0 {
t.Fatalf("setattr d: %s", st)
}
if st := m.Rename(ctx, src1, "mfile", dst1, "mfile", 0, &mfile, attr); st != syscall.EPERM {
t.Fatalf("rename d: %s", st)
}

var delFile Ino
if st := m.Create(ctx, 1, "delfile", 0644, 022, 0, &delFile, nil); st != 0 {
t.Fatalf("create f: %s", st)
}
attr.Flags = FlagImmutable | FlagAppend
if st := m.SetAttr(ctx, delFile, SetAttrFlag, 0, attr); st != 0 {
t.Fatalf("setattr d: %s", st)
}
if st := m.Unlink(ctx, 1, "delfile"); st != syscall.EPERM {
t.Fatalf("unlink f: %s", st)
}

var fallocFile Ino
if st := m.Create(ctx, 1, "fallocfile", 0644, 022, 0, &fallocFile, nil); st != 0 {
t.Fatalf("create f: %s", st)
}
attr.Flags = FlagAppend
if st := m.SetAttr(ctx, fallocFile, SetAttrFlag, 0, attr); st != 0 {
t.Fatalf("setattr f: %s", st)
}
if st := m.Fallocate(ctx, fallocFile, fallocKeepSize, 0, 1024); st != 0 {
t.Fatalf("fallocate f: %s", st)
}
if st := m.Fallocate(ctx, fallocFile, fallocKeepSize|fallocZeroRange, 0, 1024); st != syscall.EPERM {
t.Fatalf("fallocate f: %s", st)
}
attr.Flags = FlagImmutable
if st := m.SetAttr(ctx, fallocFile, SetAttrFlag, 0, attr); st != 0 {
t.Fatalf("setattr f: %s", st)
}
if st := m.Fallocate(ctx, fallocFile, fallocKeepSize, 0, 1024); st != syscall.EPERM {
t.Fatalf("fallocate f: %s", st)
}

var copysrcFile, copydstFile Ino
if st := m.Create(ctx, 1, "copysrcfile", 0644, 022, 0, &copysrcFile, nil); st != 0 {
t.Fatalf("create f: %s", st)
}
if st := m.Create(ctx, 1, "copydstfile", 0644, 022, 0, &copydstFile, nil); st != 0 {
t.Fatalf("create f: %s", st)
}
if st := m.Fallocate(ctx, copysrcFile, 0, 0, 1024); st != 0 {
t.Fatalf("fallocate f: %s", st)
}
attr.Flags = FlagAppend
if st := m.SetAttr(ctx, copydstFile, SetAttrFlag, 0, attr); st != 0 {
t.Fatalf("setattr f: %s", st)
}
if st := m.CopyFileRange(ctx, copysrcFile, 0, copydstFile, 0, 1024, 0, nil); st != syscall.EPERM {
t.Fatalf("copy_file_range f: %s", st)
}
attr.Flags = FlagImmutable
if st := m.SetAttr(ctx, copydstFile, SetAttrFlag, 0, attr); st != 0 {
t.Fatalf("setattr f: %s", st)
}
if st := m.CopyFileRange(ctx, copysrcFile, 0, copydstFile, 0, 1024, 0, nil); st != syscall.EPERM {
t.Fatalf("copy_file_range f: %s", st)
}
}
8 changes: 7 additions & 1 deletion pkg/meta/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,12 @@ const (
SetAttrCtime
SetAttrAtimeNow
SetAttrMtimeNow
SetAttrFlag = 1 << 15
)

const (
FlagImmutable = 1 << iota
FlagAppend
)

const MaxName = 255
Expand All @@ -99,7 +105,7 @@ type MsgCallback func(...interface{}) error

// Attr represents attributes of a node.
type Attr struct {
Flags uint8 // reserved flags
Flags uint8 // flags
Typ uint8 // type of a node
Mode uint16 // permission mode
Uid uint32 // owner id
Expand Down
37 changes: 37 additions & 0 deletions pkg/meta/redis.go
Original file line number Diff line number Diff line change
Expand Up @@ -930,6 +930,12 @@ func (m *redisMeta) Fallocate(ctx Context, inode Ino, mode uint8, off uint64, si
if t.Typ != TypeFile {
return syscall.EPERM
}
if (t.Flags & FlagImmutable) != 0 {
return syscall.EPERM
}
if (t.Flags&FlagAppend) != 0 && (mode&^fallocKeepSize) != 0 {
return syscall.EPERM
}
length := t.Length
if off+size > t.Length {
if mode&fallocKeepSize == 0 {
Expand Down Expand Up @@ -1037,6 +1043,10 @@ func (m *redisMeta) SetAttr(ctx Context, inode Ino, set uint16, sugidclearmode u
cur.Mtimensec = uint32(now.Nanosecond())
changed = true
}
if set&SetAttrFlag != 0 {
cur.Flags = attr.Flags
changed = true
}
if !changed {
*attr = cur
return nil
Expand Down Expand Up @@ -1106,6 +1116,9 @@ func (m *redisMeta) doMknod(ctx Context, parent Ino, name string, _type uint8, m
if pattr.Typ != TypeDirectory {
return syscall.ENOTDIR
}
if (pattr.Flags & FlagImmutable) != 0 {
return syscall.EPERM
}

buf, err := tx.HGet(ctx, m.entryKey(parent), name).Bytes()
if err != nil && err != redis.Nil {
Expand Down Expand Up @@ -1229,6 +1242,9 @@ func (m *redisMeta) doUnlink(ctx Context, parent Ino, name string) syscall.Errno
if pattr.Typ != TypeDirectory {
return syscall.ENOTDIR
}
if (pattr.Flags&FlagAppend) != 0 || (pattr.Flags&FlagImmutable) != 0 {
return syscall.EPERM
}
var updateParent bool
now := time.Now()
if !isTrash(parent) && now.Sub(time.Unix(pattr.Mtime, int64(pattr.Mtimensec))) >= minUpdateTime {
Expand All @@ -1243,6 +1259,9 @@ func (m *redisMeta) doUnlink(ctx Context, parent Ino, name string) syscall.Errno
if ctx.Uid() != 0 && pattr.Mode&01000 != 0 && ctx.Uid() != pattr.Uid && ctx.Uid() != attr.Uid {
return syscall.EACCES
}
if (attr.Flags&FlagAppend) != 0 || (attr.Flags&FlagImmutable) != 0 {
return syscall.EPERM
}
attr.Ctime = now.Unix()
attr.Ctimensec = uint32(now.Nanosecond())
if trash == 0 {
Expand Down Expand Up @@ -1349,6 +1368,9 @@ func (m *redisMeta) doRmdir(ctx Context, parent Ino, name string) syscall.Errno
if pattr.Typ != TypeDirectory {
return syscall.ENOTDIR
}
if (pattr.Flags&FlagAppend) != 0 || (pattr.Flags&FlagImmutable) != 0 {
return syscall.EPERM
}
now := time.Now()
pattr.Nlink--
pattr.Mtime = now.Unix()
Expand Down Expand Up @@ -1482,6 +1504,9 @@ func (m *redisMeta) doRename(ctx Context, parentSrc Ino, nameSrc string, parentD
return syscall.ENOTDIR
}
m.parseAttr([]byte(rs[2].(string)), &iattr)
if (sattr.Flags&FlagAppend) != 0 || (sattr.Flags&FlagImmutable) != 0 || (dattr.Flags&FlagImmutable) != 0 || (iattr.Flags&FlagAppend) != 0 || (iattr.Flags&FlagImmutable) != 0 {
return syscall.EPERM
}

var supdate, dupdate bool
now := time.Now()
Expand All @@ -1491,6 +1516,9 @@ func (m *redisMeta) doRename(ctx Context, parentSrc Ino, nameSrc string, parentD
trash = 0
}
m.parseAttr([]byte(rs[3].(string)), &tattr)
if (tattr.Flags&FlagAppend) != 0 || (tattr.Flags&FlagImmutable) != 0 {
return syscall.EPERM
}
tattr.Ctime = now.Unix()
tattr.Ctimensec = uint32(now.Nanosecond())
if exchange {
Expand Down Expand Up @@ -1666,6 +1694,9 @@ func (m *redisMeta) doLink(ctx Context, inode, parent Ino, name string, attr *At
if pattr.Typ != TypeDirectory {
return syscall.ENOTDIR
}
if pattr.Flags&FlagImmutable != 0 {
return syscall.EPERM
}
var updateParent bool
now := time.Now()
if now.Sub(time.Unix(pattr.Mtime, int64(pattr.Mtimensec))) >= minUpdateTime {
Expand All @@ -1679,6 +1710,9 @@ func (m *redisMeta) doLink(ctx Context, inode, parent Ino, name string, attr *At
if iattr.Typ == TypeDirectory {
return syscall.EPERM
}
if (iattr.Flags&FlagAppend) != 0 || (iattr.Flags&FlagImmutable) != 0 {
return syscall.EPERM
}
oldParent := iattr.Parent
iattr.Parent = 0
iattr.Ctime = now.Unix()
Expand Down Expand Up @@ -2053,6 +2087,9 @@ func (m *redisMeta) CopyFileRange(ctx Context, fin Ino, offIn uint64, fout Ino,
if attr.Typ != TypeFile {
return syscall.EINVAL
}
if (attr.Flags&FlagImmutable) != 0 || (attr.Flags&FlagAppend) != 0 {
return syscall.EPERM
}

newleng := offOut + size
if newleng > attr.Length {
Expand Down
Loading

0 comments on commit 2830ebc

Please sign in to comment.