listing drives sould use the user filter (#6103)

* listing drives shsould use the user filter

Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de>

* fix status code

Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de>

* check correct error

Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de>

* Adapt expected failures

* Bump reva

---------

Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de>
Co-authored-by: André Duffeck <andre.duffeck@firondu.de>
This commit is contained in:
Jörn Friedrich Dreyer
2023-04-28 10:06:40 +02:00
committed by GitHub
parent f0cd81f4e1
commit 3489de1c42
12 changed files with 208 additions and 41 deletions

2
go.mod
View File

@@ -13,7 +13,7 @@ require (
github.com/coreos/go-oidc v2.2.1+incompatible
github.com/coreos/go-oidc/v3 v3.4.0
github.com/cs3org/go-cs3apis v0.0.0-20221012090518-ef2996678965
github.com/cs3org/reva/v2 v2.12.1-0.20230427075231-7842414d18e1
github.com/cs3org/reva/v2 v2.12.1-0.20230428064036-4434df8122a5
github.com/disintegration/imaging v1.6.2
github.com/dutchcoders/go-clamd v0.0.0-20170520113014-b970184f4d9e
github.com/egirna/icap-client v0.1.1

4
go.sum
View File

@@ -627,8 +627,8 @@ github.com/crewjam/httperr v0.2.0 h1:b2BfXR8U3AlIHwNeFFvZ+BV1LFvKLlzMjzaTnZMybNo
github.com/crewjam/httperr v0.2.0/go.mod h1:Jlz+Sg/XqBQhyMjdDiC+GNNRzZTD7x39Gu3pglZ5oH4=
github.com/crewjam/saml v0.4.13 h1:TYHggH/hwP7eArqiXSJUvtOPNzQDyQ7vwmwEqlFWhMc=
github.com/crewjam/saml v0.4.13/go.mod h1:igEejV+fihTIlHXYP8zOec3V5A8y3lws5bQBFsTm4gA=
github.com/cs3org/reva/v2 v2.12.1-0.20230427075231-7842414d18e1 h1:p563+4bqdVSYPtDeo6ikOEbciU/mjbYhrei2zCjzxkw=
github.com/cs3org/reva/v2 v2.12.1-0.20230427075231-7842414d18e1/go.mod h1:VxBmpOvIKlgKLPOsHun+fABopzX+3ZELPAp3N5bQMsM=
github.com/cs3org/reva/v2 v2.12.1-0.20230428064036-4434df8122a5 h1:wloX5LiqRxwh2ID9O+em8O5VU1h2ZN5u6tPceAdLNDI=
github.com/cs3org/reva/v2 v2.12.1-0.20230428064036-4434df8122a5/go.mod h1:VxBmpOvIKlgKLPOsHun+fABopzX+3ZELPAp3N5bQMsM=
github.com/cubewise-code/go-mime v0.0.0-20200519001935-8c5762b177d8 h1:Z9lwXumT5ACSmJ7WGnFl+OMLLjpz5uR2fyz7dC255FI=
github.com/cubewise-code/go-mime v0.0.0-20200519001935-8c5762b177d8/go.mod h1:4abs/jPXcmJzYoYGF91JF9Uq9s/KL5n1jvFDix8KcqY=
github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4=

View File

@@ -91,6 +91,20 @@ func (g Graph) getDrives(w http.ResponseWriter, r *http.Request, unrestricted bo
errorcode.NotSupported.Render(w, r, http.StatusNotImplemented, err.Error())
return
}
if !unrestricted {
user, ok := revactx.ContextGetUser(r.Context())
if !ok {
logger.Debug().Msg("could not create drive: invalid user")
errorcode.NotAllowed.Render(w, r, http.StatusUnauthorized, "invalid user")
return
}
filters = append(filters, &storageprovider.ListStorageSpacesRequest_Filter{
Type: storageprovider.ListStorageSpacesRequest_Filter_TYPE_USER,
Term: &storageprovider.ListStorageSpacesRequest_Filter_User{
User: user.GetId(),
},
})
}
logger.Debug().
Interface("filters", filters).
@@ -240,7 +254,7 @@ func (g Graph) CreateDrive(w http.ResponseWriter, r *http.Request) {
if !canCreateSpace {
logger.Debug().Bool("cancreatespace", canCreateSpace).Msg("could not create drive: insufficient permissions")
// if the permission is not existing for the user in context we can assume we don't have it. Return 401.
errorcode.NotAllowed.Render(w, r, http.StatusUnauthorized, "insufficient permissions to create a space.")
errorcode.NotAllowed.Render(w, r, http.StatusForbidden, "insufficient permissions to create a space.")
return
}

View File

@@ -90,6 +90,7 @@ var _ = Describe("Graph", func() {
}, nil)
r := httptest.NewRequest(http.MethodGet, "/graph/v1.0/me/drives", nil)
r = r.WithContext(ctx)
rr := httptest.NewRecorder()
svc.GetDrives(rr, r)
Expect(rr.Code).To(Equal(http.StatusOK))
@@ -102,6 +103,7 @@ var _ = Describe("Graph", func() {
}, nil)
r := httptest.NewRequest(http.MethodGet, "/graph/v1.0/drives", nil)
r = r.WithContext(ctx)
rr := httptest.NewRecorder()
svc.GetAllDrives(rr, r)
Expect(rr.Code).To(Equal(http.StatusOK))
@@ -131,6 +133,7 @@ var _ = Describe("Graph", func() {
}, nil)
r := httptest.NewRequest(http.MethodGet, "/graph/v1.0/me/drives", nil)
r = r.WithContext(ctx)
rr := httptest.NewRecorder()
svc.GetDrives(rr, r)
@@ -201,6 +204,7 @@ var _ = Describe("Graph", func() {
}, nil)
r := httptest.NewRequest(http.MethodGet, "/graph/v1.0/me/drives?$orderby=name%20asc", nil)
r = r.WithContext(ctx)
rr := httptest.NewRecorder()
svc.GetDrives(rr, r)
@@ -281,6 +285,7 @@ var _ = Describe("Graph", func() {
}, nil)
r := httptest.NewRequest(http.MethodGet, "/graph/v1.0/me/drives", nil)
r = r.WithContext(ctx)
rr := httptest.NewRecorder()
svc.GetDrives(rr, r)
@@ -320,6 +325,7 @@ var _ = Describe("Graph", func() {
}, nil)
r := httptest.NewRequest(http.MethodGet, "/graph/v1.0/me/drives?$orderby=owner%20asc", nil)
r = r.WithContext(ctx)
rr := httptest.NewRecorder()
svc.GetDrives(rr, r)
Expect(rr.Code).To(Equal(http.StatusBadRequest))
@@ -361,6 +367,7 @@ var _ = Describe("Graph", func() {
gatewayClient.On("ListStorageSpaces", mock.Anything, mock.Anything).Return(nil, errors.New("transport error"))
r := httptest.NewRequest(http.MethodGet, "/graph/v1.0/me/drives)", nil)
r = r.WithContext(ctx)
rr := httptest.NewRecorder()
svc.GetDrives(rr, r)
Expect(rr.Code).To(Equal(http.StatusInternalServerError))
@@ -378,6 +385,7 @@ var _ = Describe("Graph", func() {
StorageSpaces: []*provider.StorageSpace{}}, nil)
r := httptest.NewRequest(http.MethodGet, "/graph/v1.0/me/drives)", nil)
r = r.WithContext(ctx)
rr := httptest.NewRecorder()
svc.GetDrives(rr, r)
Expect(rr.Code).To(Equal(http.StatusInternalServerError))
@@ -395,6 +403,7 @@ var _ = Describe("Graph", func() {
StorageSpaces: []*provider.StorageSpace{}}, nil)
r := httptest.NewRequest(http.MethodGet, "/graph/v1.0/me/drives)", nil)
r = r.WithContext(ctx)
rr := httptest.NewRecorder()
svc.GetDrives(rr, r)
Expect(rr.Code).To(Equal(http.StatusOK))
@@ -430,6 +439,7 @@ var _ = Describe("Graph", func() {
}, nil)
r := httptest.NewRequest(http.MethodGet, "/graph/v1.0/me/drives", nil)
r = r.WithContext(ctx)
rr := httptest.NewRecorder()
svc.GetDrives(rr, r)
@@ -469,7 +479,7 @@ var _ = Describe("Graph", func() {
r := httptest.NewRequest(http.MethodPost, "/graph/v1.0/drives", bytes.NewBuffer(jsonBody)).WithContext(ctx)
rr := httptest.NewRecorder()
svc.CreateDrive(rr, r)
Expect(rr.Code).To(Equal(http.StatusUnauthorized))
Expect(rr.Code).To(Equal(http.StatusForbidden))
body, _ := io.ReadAll(rr.Body)
var libreError libregraph.OdataError

View File

@@ -146,8 +146,6 @@ The expected failures in this file are from features in the owncloud/ocis repo.
- [apiGraph/removeUserFromGroup.feature:192](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/apiGraph/removeUserFromGroup.feature#L192)
- [apiGraph/removeUserFromGroup.feature:193](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/apiGraph/removeUserFromGroup.feature#L193)
- [apiGraph/removeUserFromGroup.feature:194](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/apiGraph/removeUserFromGroup.feature#L194)
- [apiSpaces/createSpace.feature:18](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/apiSpaces/createSpace.feature#L18)
- [apiSpaces/createSpace.feature:19](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/apiSpaces/createSpace.feature#L19)
#### [API requests for a non-existent resources should return 404](https://github.com/owncloud/ocis/issues/5939)
- [apiGraph/addUserToGroup.feature:202](https://github.com/owncloud/ocis/blob/master/tests/acceptance/features/apiGraph/addUserToGroup.feature#L202)

View File

@@ -57,6 +57,7 @@ import (
"github.com/cs3org/reva/v2/pkg/storage/utils/templates"
"github.com/cs3org/reva/v2/pkg/storagespace"
"github.com/cs3org/reva/v2/pkg/utils"
"github.com/jellydator/ttlcache/v2"
"github.com/pkg/errors"
"golang.org/x/sync/errgroup"
)
@@ -95,6 +96,8 @@ type Decomposedfs struct {
chunkHandler *chunking.ChunkHandler
stream events.Stream
cache cache.StatCache
UserCache *ttlcache.Cache
}
// NewDefault returns an instance with default components
@@ -160,6 +163,7 @@ func New(o *options.Options, lu *lookup.Lookup, p Permissions, tp Tree, es event
chunkHandler: chunking.NewChunkHandler(filepath.Join(o.Root, "uploads")),
stream: es,
cache: cache.GetStatCache(o.StatCache.Store, o.StatCache.Nodes, o.StatCache.Database, "stat", time.Duration(o.StatCache.TTL)*time.Second, o.StatCache.Size),
UserCache: ttlcache.NewCache(),
}
if o.AsyncFileUploads {

View File

@@ -201,8 +201,6 @@ func (fs *Decomposedfs) RemoveGrant(ctx context.Context, ref *provider.Reference
return err
}
spaceGrant := ctx.Value(utils.SpaceGrant)
var attr string
if g.Grantee.Type == provider.GranteeType_GRANTEE_TYPE_GROUP {
attr = prefixes.GrantGroupAcePrefix + g.Grantee.GetGroupId().OpaqueId
@@ -214,18 +212,34 @@ func (fs *Decomposedfs) RemoveGrant(ctx context.Context, ref *provider.Reference
return err
}
// TODO we need an index for groups
if spaceGrant != nil && g.Grantee.Type != provider.GranteeType_GRANTEE_TYPE_GROUP {
// remove from user index
userIDPath := filepath.Join(fs.o.Root, "indexes", "by-user-id", g.Grantee.GetUserId().OpaqueId, grantNode.SpaceID)
if err := os.Remove(userIDPath); err != nil {
return err
if isShareGrant(ctx) {
// do not invalidate by user or group indexes
// FIXME we should invalidate the by-type index, but that requires reference counting
} else {
// invalidate space grant
switch {
case g.Grantee.Type == provider.GranteeType_GRANTEE_TYPE_USER:
// remove from user index
userIDPath := filepath.Join(fs.o.Root, "indexes", "by-user-id", g.Grantee.GetUserId().GetOpaqueId(), grantNode.SpaceID)
if err := os.Remove(userIDPath); err != nil {
return err
}
case g.Grantee.Type == provider.GranteeType_GRANTEE_TYPE_GROUP:
// remove from group index
userIDPath := filepath.Join(fs.o.Root, "indexes", "by-group-id", g.Grantee.GetGroupId().GetOpaqueId(), grantNode.SpaceID)
if err := os.Remove(userIDPath); err != nil {
return err
}
}
}
return fs.tp.Propagate(ctx, grantNode, 0)
}
func isShareGrant(ctx context.Context) bool {
return ctx.Value(utils.SpaceGrant) == nil
}
// UpdateGrant updates a grant on a resource
// TODO remove AddGrant or UpdateGrant grant from CS3 api, redundant? tracked in https://github.com/cs3org/cs3apis/issues/92
func (fs *Decomposedfs) UpdateGrant(ctx context.Context, ref *provider.Reference, g *provider.Grant) error {
@@ -319,7 +333,7 @@ func (fs *Decomposedfs) storeGrant(ctx context.Context, n *node.Node, g *provide
}
// update the indexes only after successfully setting the grant
err := fs.updateIndexes(ctx, g.GetGrantee().GetUserId().GetOpaqueId(), spaceType, n.ID)
err := fs.updateIndexes(ctx, g.GetGrantee(), spaceType, n.ID)
if err != nil {
return err
}

View File

@@ -1046,19 +1046,46 @@ func (n *Node) ReadUserPermissions(ctx context.Context, u *userpb.User) (ap prov
// IsDenied checks if the node was denied to that user
func (n *Node) IsDenied(ctx context.Context) bool {
u := ctxpkg.ContextMustGetUser(ctx)
userace := prefixes.GrantUserAcePrefix + u.Id.OpaqueId
g, err := n.ReadGrant(ctx, userace)
switch {
case err == nil:
// If all permissions are set to false we have a deny grant
return grants.PermissionsEqual(g.Permissions, &provider.ResourcePermissions{})
case metadata.IsAttrUnset(err):
return false
default:
gs, err := n.ListGrants(ctx)
if err != nil {
// be paranoid, resource is denied
return true
}
u := ctxpkg.ContextMustGetUser(ctx)
isExecutant := func(g *provider.Grantee) bool {
switch g.GetType() {
case provider.GranteeType_GRANTEE_TYPE_USER:
return g.GetUserId().GetOpaqueId() == u.GetId().GetOpaqueId()
case provider.GranteeType_GRANTEE_TYPE_GROUP:
// check gid
gid := g.GetGroupId().GetOpaqueId()
for _, group := range u.Groups {
if gid == group {
return true
}
}
return false
default:
return false
}
}
for _, g := range gs {
if !isExecutant(g.Grantee) {
continue
}
if grants.PermissionsEqual(g.Permissions, &provider.ResourcePermissions{}) {
// resource is denied
return true
}
}
// no deny grants
return false
}
// ListGrantees lists the grantees of the current node

View File

@@ -35,6 +35,9 @@ type Option func(o *Options)
// Options defines the available options for this package.
type Options struct {
// the gateway address
GatewayAddr string `mapstructure:"gateway_addr"`
// the metadata backend to use, currently supports `xattr` or `ini`
MetadataBackend string `mapstructure:"metadata_backend"`
@@ -99,6 +102,8 @@ func New(m map[string]interface{}) (*Options, error) {
return nil, err
}
o.GatewayAddr = sharedconf.GetGatewaySVC(o.GatewayAddr)
if o.MetadataBackend == "" {
o.MetadataBackend = "xattrs"
}

View File

@@ -3,11 +3,13 @@ package decomposedfs
import (
"context"
userv1beta1 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
cs3permissions "github.com/cs3org/go-cs3apis/cs3/permissions/v1beta1"
v1beta11 "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
ctxpkg "github.com/cs3org/reva/v2/pkg/ctx"
"github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/node"
"github.com/cs3org/reva/v2/pkg/utils"
"google.golang.org/grpc"
)
@@ -70,12 +72,12 @@ func (p Permissions) ListAllSpaces(ctx context.Context) bool {
}
// ListSpacesOfUser returns true when the user is allowed to list the spaces of the given user
func (p Permissions) ListSpacesOfUser(ctx context.Context, userid string) bool {
switch userid {
case userIDAny:
func (p Permissions) ListSpacesOfUser(ctx context.Context, userid *userv1beta1.UserId) bool {
switch {
case userid == nil:
// there is no filter
return true // TODO: is `true` actually correct here? Shouldn't we check for ListAllSpaces too?
case ctxpkg.ContextMustGetUser(ctx).GetId().GetOpaqueId():
case utils.UserIDEqual(ctxpkg.ContextMustGetUser(ctx).GetId(), userid):
return true
default:
return p.ListAllSpaces(ctx)

View File

@@ -37,6 +37,7 @@ import (
ctxpkg "github.com/cs3org/reva/v2/pkg/ctx"
"github.com/cs3org/reva/v2/pkg/errtypes"
"github.com/cs3org/reva/v2/pkg/rgrpc/status"
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
"github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/lookup"
"github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/metadata/prefixes"
"github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/node"
@@ -54,13 +55,13 @@ const (
spaceTypeShare = "share"
spaceTypeAny = "*"
spaceIDAny = "*"
userIDAny = "*"
quotaUnrestricted = 0
)
// CreateStorageSpace creates a storage space
func (fs *Decomposedfs) CreateStorageSpace(ctx context.Context, req *provider.CreateStorageSpaceRequest) (*provider.CreateStorageSpaceResponse, error) {
ctx = context.WithValue(ctx, utils.SpaceGrant, struct{}{})
// "everything is a resource" this is the unique ID for the Space resource.
spaceID := uuid.New().String()
@@ -147,7 +148,10 @@ func (fs *Decomposedfs) CreateStorageSpace(ctx context.Context, req *provider.Cr
}
// Write index
err = fs.updateIndexes(ctx, req.GetOwner().GetId().GetOpaqueId(), req.Type, root.ID)
err = fs.updateIndexes(ctx, &provider.Grantee{
Type: provider.GranteeType_GRANTEE_TYPE_USER,
Id: &provider.Grantee_UserId{UserId: req.GetOwner().GetId()},
}, req.Type, root.ID)
if err != nil {
return nil, err
}
@@ -218,7 +222,7 @@ func (fs *Decomposedfs) ListStorageSpaces(ctx context.Context, filter []*provide
var (
spaceID = spaceIDAny
nodeID = spaceIDAny
requestedUserID = userIDAny
requestedUserID *userv1beta1.UserId
)
spaceTypes := map[string]struct{}{}
@@ -241,10 +245,10 @@ func (fs *Decomposedfs) ListStorageSpaces(ctx context.Context, filter []*provide
}
case provider.ListStorageSpacesRequest_Filter_TYPE_USER:
// TODO: refactor this to GetUserId() in cs3
requestedUserID = filter[i].GetUser().GetOpaqueId()
requestedUserID = filter[i].GetUser()
case provider.ListStorageSpacesRequest_Filter_TYPE_OWNER:
// TODO: improve further by not evaluating shares
requestedUserID = filter[i].GetOwner().GetOpaqueId()
requestedUserID = filter[i].GetOwner()
}
}
if len(spaceTypes) == 0 {
@@ -292,8 +296,8 @@ func (fs *Decomposedfs) ListStorageSpaces(ctx context.Context, filter []*provide
matches := map[string]struct{}{}
if requestedUserID != userIDAny {
path := filepath.Join(fs.o.Root, "indexes", "by-user-id", requestedUserID, nodeID)
if requestedUserID != nil {
path := filepath.Join(fs.o.Root, "indexes", "by-user-id", requestedUserID.GetOpaqueId(), nodeID)
m, err := filepath.Glob(path)
if err != nil {
return nil, err
@@ -305,9 +309,35 @@ func (fs *Decomposedfs) ListStorageSpaces(ctx context.Context, filter []*provide
}
matches[link] = struct{}{}
}
// get Groups for userid
user := ctxpkg.ContextMustGetUser(ctx)
// TODO the user from context may not have groups populated
if !utils.UserIDEqual(user.GetId(), requestedUserID) {
user, err = fs.UserIDToUserAndGroups(ctx, requestedUserID)
if err != nil {
return nil, err // TODO log and continue?
}
}
for _, group := range user.Groups {
path := filepath.Join(fs.o.Root, "indexes", "by-group-id", group, nodeID)
m, err := filepath.Glob(path)
if err != nil {
return nil, err
}
for _, match := range m {
link, err := os.Readlink(match)
if err != nil {
continue
}
matches[link] = struct{}{}
}
}
}
if requestedUserID == userIDAny {
if requestedUserID == nil {
for spaceType := range spaceTypes {
path := filepath.Join(fs.o.Root, "indexes", "by-type", spaceType, nodeID)
m, err := filepath.Glob(path)
@@ -412,6 +442,31 @@ func (fs *Decomposedfs) ListStorageSpaces(ctx context.Context, filter []*provide
}
// UserIDToUserAndGroups converts a user ID to a user with groups
func (fs *Decomposedfs) UserIDToUserAndGroups(ctx context.Context, userid *userv1beta1.UserId) (*userv1beta1.User, error) {
user, err := fs.UserCache.Get(userid.GetOpaqueId())
if err == nil {
return user.(*userv1beta1.User), nil
}
gwConn, err := pool.GetGatewayServiceClient(fs.o.GatewayAddr)
if err != nil {
return nil, err
}
getUserResponse, err := gwConn.GetUser(ctx, &userv1beta1.GetUserRequest{
UserId: userid,
SkipFetchingUserGroups: false,
})
if err != nil {
return nil, err
}
if getUserResponse.Status.Code != v1beta11.Code_CODE_OK {
return nil, status.NewErrorFromCode(getUserResponse.Status.Code, "gateway")
}
_ = fs.UserCache.Set(userid.GetOpaqueId(), getUserResponse.GetUser())
return getUserResponse.GetUser(), nil
}
// MustCheckNodePermissions checks if permission checks are needed to be performed when user requests spaces
func (fs *Decomposedfs) MustCheckNodePermissions(ctx context.Context, unrestricted bool) bool {
// canListAllSpaces indicates if the user has the permission from the global user role
@@ -649,12 +704,26 @@ func (fs *Decomposedfs) DeleteStorageSpace(ctx context.Context, req *provider.De
return n.SetDTime(&dtime)
}
func (fs *Decomposedfs) updateIndexes(ctx context.Context, userID, spaceType, spaceID string) error {
func (fs *Decomposedfs) updateIndexes(ctx context.Context, grantee *provider.Grantee, spaceType, spaceID string) error {
err := fs.linkStorageSpaceType(ctx, spaceType, spaceID)
if err != nil {
return err
}
return fs.linkSpaceByUser(ctx, userID, spaceID)
if isShareGrant(ctx) {
// FIXME we should count the references for the by-type index currently removing the second share from the same
// space cannot determine if the by-type should be deletet, which is why we never delete them ...
return nil
}
// create space grant index
switch {
case grantee.Type == provider.GranteeType_GRANTEE_TYPE_USER:
return fs.linkSpaceByUser(ctx, grantee.GetUserId().GetOpaqueId(), spaceID)
case grantee.Type == provider.GranteeType_GRANTEE_TYPE_GROUP:
return fs.linkSpaceByGroup(ctx, grantee.GetGroupId().GetOpaqueId(), spaceID)
default:
return errtypes.BadRequest("invalid grantee type: " + grantee.GetType().String())
}
}
func (fs *Decomposedfs) linkSpaceByUser(ctx context.Context, userID, spaceID string) error {
@@ -681,6 +750,30 @@ func (fs *Decomposedfs) linkSpaceByUser(ctx context.Context, userID, spaceID str
return nil
}
func (fs *Decomposedfs) linkSpaceByGroup(ctx context.Context, groupID, spaceID string) error {
if groupID == "" {
return nil
}
// create group index dir
// TODO: pathify groupid
if err := os.MkdirAll(filepath.Join(fs.o.Root, "indexes", "by-group-id", groupID), 0700); err != nil {
return err
}
err := os.Symlink("../../../spaces/"+lookup.Pathify(spaceID, 1, 2)+"/nodes/"+lookup.Pathify(spaceID, 4, 2), filepath.Join(fs.o.Root, "indexes/by-group-id", groupID, spaceID))
if err != nil {
if isAlreadyExists(err) {
appctx.GetLogger(ctx).Debug().Err(err).Str("space", spaceID).Str("group-id", groupID).Msg("symlink already exists")
// FIXME: is it ok to wipe this err if the symlink already exists?
err = nil //nolint
} else {
// TODO how should we handle error cases here?
appctx.GetLogger(ctx).Error().Err(err).Str("space", spaceID).Str("group-id", groupID).Msg("could not create symlink")
}
}
return nil
}
// TODO: implement linkSpaceByGroup
func (fs *Decomposedfs) linkStorageSpaceType(ctx context.Context, spaceType string, spaceID string) error {

2
vendor/modules.txt vendored
View File

@@ -349,7 +349,7 @@ github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1
github.com/cs3org/go-cs3apis/cs3/storage/registry/v1beta1
github.com/cs3org/go-cs3apis/cs3/tx/v1beta1
github.com/cs3org/go-cs3apis/cs3/types/v1beta1
# github.com/cs3org/reva/v2 v2.12.1-0.20230427075231-7842414d18e1
# github.com/cs3org/reva/v2 v2.12.1-0.20230428064036-4434df8122a5
## explicit; go 1.19
github.com/cs3org/reva/v2/cmd/revad/internal/grace
github.com/cs3org/reva/v2/cmd/revad/runtime