From e55c1157726dc7b6229eabdc4b57a384dcd30c48 Mon Sep 17 00:00:00 2001 From: Michael Barz Date: Fri, 11 Feb 2022 13:18:51 +0100 Subject: [PATCH] Add space props (#2527) * add space properties * add changelog * handle write error * optimize and send back the updated space * add permission checks --- .../unreleased/change-space-attributes.md | 5 + pkg/storage/utils/decomposedfs/spaces.go | 117 ++++++++++++++++-- .../utils/decomposedfs/xattrs/xattrs.go | 5 +- 3 files changed, 116 insertions(+), 11 deletions(-) create mode 100644 changelog/unreleased/change-space-attributes.md diff --git a/changelog/unreleased/change-space-attributes.md b/changelog/unreleased/change-space-attributes.md new file mode 100644 index 0000000000..250c2d36dd --- /dev/null +++ b/changelog/unreleased/change-space-attributes.md @@ -0,0 +1,5 @@ +Change: Store space attributes in decomposedFS + +We need to store more space attributes in the storage. This implements extended space attributes in the decomposedFS + +https://github.com/cs3org/reva/pull/2527 \ No newline at end of file diff --git a/pkg/storage/utils/decomposedfs/spaces.go b/pkg/storage/utils/decomposedfs/spaces.go index 957cd3ce2d..b847bd3ce4 100644 --- a/pkg/storage/utils/decomposedfs/spaces.go +++ b/pkg/storage/utils/decomposedfs/spaces.go @@ -387,21 +387,62 @@ func (fs *Decomposedfs) UpdateStorageSpace(ctx context.Context, req *provider.Up } space.Owner = u + metadata := make(map[string]string, 5) if space.Name != "" { - if err := node.SetMetadata(xattrs.SpaceNameAttr, space.Name); err != nil { - return nil, err - } + metadata[xattrs.SpaceNameAttr] = space.Name } if space.Quota != nil { - if err := node.SetMetadata(xattrs.QuotaAttr, strconv.FormatUint(space.Quota.QuotaMaxBytes, 10)); err != nil { - return nil, err + metadata[xattrs.QuotaAttr] = strconv.FormatUint(space.Quota.QuotaMaxBytes, 10) + } + + // TODO also return values which are not in the request + hasDescription := false + if space.Opaque != nil { + if description, ok := space.Opaque.Map["description"]; ok { + metadata[xattrs.SpaceDescriptionAttr] = string(description.Value) + hasDescription = true + } + if image, ok := space.Opaque.Map["image"]; ok { + metadata[xattrs.SpaceImageAttr] = string(image.Value) + } + if readme, ok := space.Opaque.Map["readme"]; ok { + metadata[xattrs.SpaceReadmeAttr] = string(readme.Value) } } + // TODO change the permission handling + // these two attributes need manager permissions + if space.Name != "" || hasDescription { + err = fs.checkManagerPermission(ctx, node) + } + if err != nil { + return &provider.UpdateStorageSpaceResponse{ + Status: &v1beta11.Status{Code: v1beta11.Code_CODE_PERMISSION_DENIED, Message: err.Error()}, + }, nil + } + // all other attributes need editor permissions + err = fs.checkEditorPermission(ctx, node) + if err != nil { + return &provider.UpdateStorageSpaceResponse{ + Status: &v1beta11.Status{Code: v1beta11.Code_CODE_PERMISSION_DENIED, Message: err.Error()}, + }, nil + } + + err = xattrs.SetMultiple(node.InternalPath(), metadata) + if err != nil { + return nil, err + } + + // send back the updated data from the storage + updatedSpace, err := fs.storageSpaceFromNode(ctx, node, "*", node.InternalPath(), false) + if err != nil { + return nil, err + } + return &provider.UpdateStorageSpaceResponse{ Status: &v1beta11.Status{Code: v1beta11.Code_CODE_OK}, - StorageSpace: space, + StorageSpace: updatedSpace, }, nil } @@ -634,15 +675,20 @@ func (fs *Decomposedfs) storageSpaceFromNode(ctx context.Context, n *node.Node, } } + spaceAttributes, err := xattrs.All(nodePath) + if err != nil { + return nil, err + } + // quota - v, err := xattrs.Get(nodePath, xattrs.QuotaAttr) - if err == nil { + quotaAttr, ok := spaceAttributes[xattrs.QuotaAttr] + if ok { // make sure we have a proper signed int // we use the same magic numbers to indicate: // -1 = uncalculated // -2 = unknown // -3 = unlimited - if quota, err := strconv.ParseUint(v, 10, 64); err == nil { + if quota, err := strconv.ParseUint(quotaAttr, 10, 64); err == nil { space.Quota = &provider.Quota{ QuotaMaxBytes: quota, QuotaMaxFiles: math.MaxUint64, // TODO MaxUInt64? = unlimited? why even max files? 0 = unlimited? @@ -651,6 +697,57 @@ func (fs *Decomposedfs) storageSpaceFromNode(ctx context.Context, n *node.Node, return nil, err } } - + spaceImage, ok := spaceAttributes[xattrs.SpaceImageAttr] + if ok { + space.Opaque.Map["image"] = &types.OpaqueEntry{ + Decoder: "plain", + Value: []byte(spaceImage), + } + } + spaceDescription, ok := spaceAttributes[xattrs.SpaceDescriptionAttr] + if ok { + space.Opaque.Map["description"] = &types.OpaqueEntry{ + Decoder: "plain", + Value: []byte(spaceDescription), + } + } + spaceReadme, ok := spaceAttributes[xattrs.SpaceReadmeAttr] + if ok { + space.Opaque.Map["readme"] = &types.OpaqueEntry{ + Decoder: "plain", + Value: []byte(spaceReadme), + } + } return space, nil } + +func (fs *Decomposedfs) checkManagerPermission(ctx context.Context, n *node.Node) error { + // to update the space name or short description we need the manager role + // current workaround: check if AddGrant Permission exists + managerPerm, err := fs.p.HasPermission(ctx, n, func(rp *provider.ResourcePermissions) bool { + return rp.AddGrant + }) + switch { + case err != nil: + return errtypes.InternalError(err.Error()) + case !managerPerm: + msg := fmt.Sprintf("not enough permissions to change attributes on %s", filepath.Join(n.ParentID, n.Name)) + return errtypes.PermissionDenied(msg) + } + return nil +} + +func (fs *Decomposedfs) checkEditorPermission(ctx context.Context, n *node.Node) error { + // current workaround: check if InitiateFileUpload Permission exists + editorPerm, err := fs.p.HasPermission(ctx, n, func(rp *provider.ResourcePermissions) bool { + return rp.InitiateFileUpload + }) + switch { + case err != nil: + return errtypes.InternalError(err.Error()) + case !editorPerm: + msg := fmt.Sprintf("not enough permissions to change attributes on %s", filepath.Join(n.ParentID, n.Name)) + return errtypes.PermissionDenied(msg) + } + return nil +} diff --git a/pkg/storage/utils/decomposedfs/xattrs/xattrs.go b/pkg/storage/utils/decomposedfs/xattrs/xattrs.go index f65900c202..2f7b3f1942 100644 --- a/pkg/storage/utils/decomposedfs/xattrs/xattrs.go +++ b/pkg/storage/utils/decomposedfs/xattrs/xattrs.go @@ -83,7 +83,10 @@ const ( QuotaAttr string = OcisPrefix + "quota" // the name given to a storage space. It should not contain any semantics as its only purpose is to be read. - SpaceNameAttr string = OcisPrefix + "space.name" + SpaceNameAttr string = OcisPrefix + "space.name" + SpaceDescriptionAttr string = OcisPrefix + "space.description" + SpaceReadmeAttr string = OcisPrefix + "space.readme" + SpaceImageAttr string = OcisPrefix + "space.image" UserAcePrefix string = "u:" GroupAcePrefix string = "g:"