Skip to content

Commit 6b3bfab

Browse files
committed
Propagate file ownership via NFSv4
NFSv4 has FATTR4_OWNER and FATTR4_OWNER_GROUP fields that can be used to announce file ownership. Unlike FUSE, these are strings. For our use case it's sufficient to always set them to a decimal value of the user/group ID.
1 parent 8175394 commit 6b3bfab

File tree

3 files changed

+85
-3
lines changed

3 files changed

+85
-3
lines changed

pkg/filesystem/virtual/nfsv4/nfs40_program.go

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"context"
66
"io"
77
"math"
8+
"strconv"
89
"sync"
910
"time"
1011

@@ -560,6 +561,8 @@ func (p *nfs40Program) writeAttributes(attributes *virtual.Attributes, attrReque
560561
(1 << nfsv4.FATTR4_FILEID),
561562
(1 << (nfsv4.FATTR4_MODE - 32)) |
562563
(1 << (nfsv4.FATTR4_NUMLINKS - 32)) |
564+
(1 << (nfsv4.FATTR4_OWNER - 32)) |
565+
(1 << (nfsv4.FATTR4_OWNER_GROUP - 32)) |
563566
(1 << (nfsv4.FATTR4_TIME_ACCESS - 32)) |
564567
(1 << (nfsv4.FATTR4_TIME_METADATA - 32)) |
565568
(1 << (nfsv4.FATTR4_TIME_MODIFY - 32)),
@@ -657,6 +660,25 @@ func (p *nfs40Program) writeAttributes(attributes *virtual.Attributes, attrReque
657660
s |= b
658661
nfsv4.WriteUint32T(w, attributes.GetLinkCount())
659662
}
663+
if b := uint32(1 << (nfsv4.FATTR4_OWNER - 32)); f&b != 0 {
664+
// The macOS NFSv4 driver requires that if
665+
// FATTR4_OWNER is a supported attribute, all
666+
// files in the file system report it.
667+
s |= b
668+
v := ""
669+
if ownerUserID, ok := attributes.GetOwnerUserID(); ok {
670+
v = strconv.FormatUint(uint64(ownerUserID), 10)
671+
}
672+
nfsv4.WriteUtf8strMixed(w, v)
673+
}
674+
if b := uint32(1 << (nfsv4.FATTR4_OWNER_GROUP - 32)); f&b != 0 {
675+
s |= b
676+
v := ""
677+
if ownerGroupID, ok := attributes.GetOwnerGroupID(); ok {
678+
v = strconv.FormatUint(uint64(ownerGroupID), 10)
679+
}
680+
nfsv4.WriteUtf8strMixed(w, v)
681+
}
660682
if b := uint32(1 << (nfsv4.FATTR4_TIME_ACCESS - 32)); f&b != 0 {
661683
s |= b
662684
deterministicNfstime4.WriteTo(w)
@@ -3026,6 +3048,12 @@ func attrRequestToAttributesMask(attrRequest nfsv4.Bitmap4) virtual.AttributesMa
30263048
if f&uint32(1<<(nfsv4.FATTR4_NUMLINKS-32)) != 0 {
30273049
attributesMask |= virtual.AttributesMaskLinkCount
30283050
}
3051+
if f&uint32(1<<(nfsv4.FATTR4_OWNER-32)) != 0 {
3052+
attributesMask |= virtual.AttributesMaskOwnerUserID
3053+
}
3054+
if f&uint32(1<<(nfsv4.FATTR4_OWNER_GROUP-32)) != 0 {
3055+
attributesMask |= virtual.AttributesMaskOwnerGroupID
3056+
}
30293057
if f&uint32(1<<(nfsv4.FATTR4_TIME_MODIFY-32)) != 0 {
30303058
attributesMask |= virtual.AttributesMaskLastDataModificationTime
30313059
}
@@ -3044,6 +3072,12 @@ func attributesMaskToBitmap4(in virtual.AttributesMask) []uint32 {
30443072
if in&virtual.AttributesMaskPermissions != 0 {
30453073
out[1] |= (1 << (nfsv4.FATTR4_MODE - 32))
30463074
}
3075+
if in&virtual.AttributesMaskOwnerUserID != 0 {
3076+
out[1] |= (1 << (nfsv4.FATTR4_OWNER - 32))
3077+
}
3078+
if in&virtual.AttributesMaskOwnerGroupID != 0 {
3079+
out[1] |= (1 << (nfsv4.FATTR4_OWNER_GROUP - 32))
3080+
}
30473081
if in&virtual.AttributesMaskSizeBytes != 0 {
30483082
out[0] |= (1 << nfsv4.FATTR4_SIZE)
30493083
}
@@ -3172,7 +3206,9 @@ func fattr4ToAttributes(in *nfsv4.Fattr4, out *virtual.Attributes) nfsv4.Nfsstat
31723206
if len(in.Attrmask) > 1 {
31733207
// Attributes 32 to 63.
31743208
f := in.Attrmask[1]
3175-
if f&^(1<<(nfsv4.FATTR4_MODE-32)) != 0 {
3209+
if f&^((1<<(nfsv4.FATTR4_MODE-32))|
3210+
(1<<(nfsv4.FATTR4_OWNER-32))|
3211+
(1<<(nfsv4.FATTR4_OWNER_GROUP-32))) != 0 {
31763212
return nfsv4.NFS4ERR_ATTRNOTSUPP
31773213
}
31783214
if f&(1<<(nfsv4.FATTR4_MODE-32)) != 0 {
@@ -3182,6 +3218,9 @@ func fattr4ToAttributes(in *nfsv4.Fattr4, out *virtual.Attributes) nfsv4.Nfsstat
31823218
}
31833219
out.SetPermissions(virtual.NewPermissionsFromMode(mode))
31843220
}
3221+
if f&((1<<(nfsv4.FATTR4_OWNER-32))|(1<<(nfsv4.FATTR4_OWNER_GROUP-32))) != 0 {
3222+
return nfsv4.NFS4ERR_PERM
3223+
}
31853224
}
31863225
for i := 2; i < len(in.Attrmask); i++ {
31873226
// Attributes 64 or higher.

pkg/filesystem/virtual/nfsv4/nfs40_program_test.go

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1681,7 +1681,16 @@ func TestNFS40ProgramCompound_OP_GETATTR(t *testing.T) {
16811681
// Request all supported attributes.
16821682
rootDirectory.EXPECT().VirtualGetAttributes(
16831683
ctx,
1684-
virtual.AttributesMaskChangeID|virtual.AttributesMaskFileHandle|virtual.AttributesMaskFileType|virtual.AttributesMaskInodeNumber|virtual.AttributesMaskLastDataModificationTime|virtual.AttributesMaskLinkCount|virtual.AttributesMaskPermissions|virtual.AttributesMaskSizeBytes,
1684+
virtual.AttributesMaskChangeID|
1685+
virtual.AttributesMaskFileHandle|
1686+
virtual.AttributesMaskFileType|
1687+
virtual.AttributesMaskInodeNumber|
1688+
virtual.AttributesMaskLastDataModificationTime|
1689+
virtual.AttributesMaskLinkCount|
1690+
virtual.AttributesMaskOwnerGroupID|
1691+
virtual.AttributesMaskOwnerUserID|
1692+
virtual.AttributesMaskPermissions|
1693+
virtual.AttributesMaskSizeBytes,
16851694
gomock.Any(),
16861695
).Do(func(ctx context.Context, requested virtual.AttributesMask, attributes *virtual.Attributes) {
16871696
attributes.SetChangeID(0xeaab7253dad16ee5)
@@ -1690,6 +1699,8 @@ func TestNFS40ProgramCompound_OP_GETATTR(t *testing.T) {
16901699
attributes.SetInodeNumber(0xfcadd45521cb1db2)
16911700
attributes.SetLastDataModificationTime(time.Unix(1654791566, 4839067173))
16921701
attributes.SetLinkCount(12)
1702+
attributes.SetOwnerGroupID(20)
1703+
attributes.SetOwnerUserID(501)
16931704
attributes.SetPermissions(virtual.PermissionsRead | virtual.PermissionsExecute)
16941705
attributes.SetSizeBytes(8192)
16951706
})
@@ -1716,6 +1727,8 @@ func TestNFS40ProgramCompound_OP_GETATTR(t *testing.T) {
17161727
(1 << nfsv4_xdr.FATTR4_FILEID),
17171728
(1 << (nfsv4_xdr.FATTR4_MODE - 32)) |
17181729
(1 << (nfsv4_xdr.FATTR4_NUMLINKS - 32)) |
1730+
(1 << (nfsv4_xdr.FATTR4_OWNER - 32)) |
1731+
(1 << (nfsv4_xdr.FATTR4_OWNER_GROUP - 32)) |
17191732
(1 << (nfsv4_xdr.FATTR4_TIME_ACCESS - 32)) |
17201733
(1 << (nfsv4_xdr.FATTR4_TIME_METADATA - 32)) |
17211734
(1 << (nfsv4_xdr.FATTR4_TIME_MODIFY - 32)),
@@ -1753,6 +1766,8 @@ func TestNFS40ProgramCompound_OP_GETATTR(t *testing.T) {
17531766
(1 << nfsv4_xdr.FATTR4_FILEID),
17541767
(1 << (nfsv4_xdr.FATTR4_MODE - 32)) |
17551768
(1 << (nfsv4_xdr.FATTR4_NUMLINKS - 32)) |
1769+
(1 << (nfsv4_xdr.FATTR4_OWNER - 32)) |
1770+
(1 << (nfsv4_xdr.FATTR4_OWNER_GROUP - 32)) |
17561771
(1 << (nfsv4_xdr.FATTR4_TIME_ACCESS - 32)) |
17571772
(1 << (nfsv4_xdr.FATTR4_TIME_METADATA - 32)) |
17581773
(1 << (nfsv4_xdr.FATTR4_TIME_MODIFY - 32)),
@@ -1761,7 +1776,7 @@ func TestNFS40ProgramCompound_OP_GETATTR(t *testing.T) {
17611776
// FATTR4_SUPPORTED_ATTRS.
17621777
0x00, 0x00, 0x00, 0x02,
17631778
0x00, 0x18, 0x0f, 0xff,
1764-
0x00, 0x30, 0x80, 0x0a,
1779+
0x00, 0x30, 0x80, 0x3a,
17651780
// FATTR4_TYPE == NF4DIR.
17661781
0x00, 0x00, 0x00, 0x02,
17671782
// FATTR4_FH_EXPIRE_TYPE == FH4_PERSISTENT.
@@ -1792,6 +1807,12 @@ func TestNFS40ProgramCompound_OP_GETATTR(t *testing.T) {
17921807
0x00, 0x00, 0x01, 0x6d,
17931808
// FATTR4_NUMLINKS.
17941809
0x00, 0x00, 0x00, 0x0c,
1810+
// FATTR4_OWNER == "501".
1811+
0x00, 0x00, 0x00, 0x03,
1812+
0x35, 0x30, 0x31, 0x00,
1813+
// FATTR4_OWNER_GROUP == "20".
1814+
0x00, 0x00, 0x00, 0x02,
1815+
0x32, 0x30, 0x00, 0x00,
17951816
// FATTR4_TIME_ACCESS == 2000-01-01T00:00:00Z.
17961817
0x00, 0x00, 0x00, 0x00, 0x38, 0x6d, 0x43, 0x80,
17971818
0x00, 0x00, 0x00, 0x00,

pkg/filesystem/virtual/nfsv4/nfs41_program.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"context"
66
"encoding/binary"
77
"io"
8+
"strconv"
89
"sync"
910
"time"
1011

@@ -398,6 +399,8 @@ func (p *nfs41Program) writeAttributes(attributes *virtual.Attributes, attrReque
398399
(1 << nfsv4.FATTR4_FILEID),
399400
(1 << (nfsv4.FATTR4_MODE - 32)) |
400401
(1 << (nfsv4.FATTR4_NUMLINKS - 32)) |
402+
(1 << (nfsv4.FATTR4_OWNER - 32)) |
403+
(1 << (nfsv4.FATTR4_OWNER_GROUP - 32)) |
401404
(1 << (nfsv4.FATTR4_TIME_ACCESS - 32)) |
402405
(1 << (nfsv4.FATTR4_TIME_METADATA - 32)) |
403406
(1 << (nfsv4.FATTR4_TIME_MODIFY - 32)),
@@ -496,6 +499,25 @@ func (p *nfs41Program) writeAttributes(attributes *virtual.Attributes, attrReque
496499
s |= b
497500
nfsv4.WriteUint32T(w, attributes.GetLinkCount())
498501
}
502+
if b := uint32(1 << (nfsv4.FATTR4_OWNER - 32)); f&b != 0 {
503+
// The macOS NFSv4 driver requires that if
504+
// FATTR4_OWNER is a supported attribute, all
505+
// files in the file system report it.
506+
s |= b
507+
v := ""
508+
if ownerUserID, ok := attributes.GetOwnerUserID(); ok {
509+
v = strconv.FormatUint(uint64(ownerUserID), 10)
510+
}
511+
nfsv4.WriteUtf8strMixed(w, v)
512+
}
513+
if b := uint32(1 << (nfsv4.FATTR4_OWNER_GROUP - 32)); f&b != 0 {
514+
s |= b
515+
v := ""
516+
if ownerGroupID, ok := attributes.GetOwnerGroupID(); ok {
517+
v = strconv.FormatUint(uint64(ownerGroupID), 10)
518+
}
519+
nfsv4.WriteUtf8strMixed(w, v)
520+
}
499521
if b := uint32(1 << (nfsv4.FATTR4_TIME_ACCESS - 32)); f&b != 0 {
500522
s |= b
501523
deterministicNfstime4.WriteTo(w)

0 commit comments

Comments
 (0)