diff --git a/go.mod b/go.mod index 2731cc1bd0..d83951ad55 100644 --- a/go.mod +++ b/go.mod @@ -67,7 +67,7 @@ require ( github.com/open-policy-agent/opa v1.21.1 github.com/opencloud-eu/icap-client v0.0.0-20250930132611-28a2afe62d89 github.com/opencloud-eu/libre-graph-api-go v1.0.9-0.20261008090127-e04fc3d3e458 - github.com/opencloud-eu/reva/v2 v2.51.1-0.20261009143138-36d43ce34b87 + github.com/opencloud-eu/reva/v2 v2.51.1-0.20261014072417-be32dce83442 github.com/opensearch-project/opensearch-go/v4 v4.7.3 github.com/orcaman/concurrent-map v1.0.0 github.com/pkg/errors v0.9.1 diff --git a/go.sum b/go.sum index 2959a795fd..cc9f350046 100644 --- a/go.sum +++ b/go.sum @@ -761,8 +761,10 @@ github.com/opencloud-eu/icap-client v0.0.0-20250930132611-28a2afe62d89 h1:W1ms+l github.com/opencloud-eu/icap-client v0.0.0-20250930132611-28a2afe62d89/go.mod h1:vigJkNss1N2QEceCuNw/ullDehncuJNFB6mEnzfq9UI= github.com/opencloud-eu/libre-graph-api-go v1.0.9-0.20261008090127-e04fc3d3e458 h1:TkJT8H30iesStrBZFHhdwam2rJQA7CoOUwdpbSzxtdk= github.com/opencloud-eu/libre-graph-api-go v1.0.9-0.20261008090127-e04fc3d3e458/go.mod h1:lTM8JeGblNpoMySTW7Lui2+c5TTLI95mwxtdUIHHrhU= -github.com/opencloud-eu/reva/v2 v2.51.1-0.20261009143138-36d43ce34b87 h1:UnyTDjdtA5uS6i0tdUZ+6YcgxsCt/Uid9+gU/TL7Dic= -github.com/opencloud-eu/reva/v2 v2.51.1-0.20261009143138-36d43ce34b87/go.mod h1:rAwuI3PX8n3RxBXHfpMtAKqfwxTIKhZol1Bi3Qj39p8= +github.com/opencloud-eu/reva/v2 v2.51.1-0.20261013142211-905dc7a89649 h1:7yTv1wY/1oIYh48yQEFRavFzRqj6C9TPksXua34qTug= +github.com/opencloud-eu/reva/v2 v2.51.1-0.20261013142211-905dc7a89649/go.mod h1:rAwuI3PX8n3RxBXHfpMtAKqfwxTIKhZol1Bi3Qj39p8= +github.com/opencloud-eu/reva/v2 v2.51.1-0.20261014072417-be32dce83442 h1:O7atTisd/px+EfXMHCF3t/xigagbh83rrZ+A0jxAar4= +github.com/opencloud-eu/reva/v2 v2.51.1-0.20261014072417-be32dce83442/go.mod h1:rAwuI3PX8n3RxBXHfpMtAKqfwxTIKhZol1Bi3Qj39p8= github.com/opencloud-eu/secure v0.0.0-20260312082735-b6f5cb2244e4 h1:l2oB/RctH+t8r7QBj5p8thfEHCM/jF35aAY3WQ3hADI= github.com/opencloud-eu/secure v0.0.0-20260312082735-b6f5cb2244e4/go.mod h1:BmF5hyM6tXczk3MpQkFf1hpKSRqCyhqcbiQtiAF7+40= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= diff --git a/tests/acceptance/features/apiSharingNg1/removeAccessToDrive.feature b/tests/acceptance/features/apiSharingNg1/removeAccessToDrive.feature index 312a410125..4391fcd227 100644 --- a/tests/acceptance/features/apiSharingNg1/removeAccessToDrive.feature +++ b/tests/acceptance/features/apiSharingNg1/removeAccessToDrive.feature @@ -186,6 +186,19 @@ Feature: Remove access to a drive Then the HTTP status code should be "204" And user "Alice" should not have any "link" permissions on space "NewSpace" + + Scenario: user tries to remove an already removed link share from project space using root endpoint + Given the administrator has assigned the role "Space Admin" to user "Alice" using the Graph API + And user "Alice" has created a space "NewSpace" with the default quota using the Graph API + And user "Alice" has created the following space link share: + | space | NewSpace | + | permissionsRole | view | + | password | %public% | + And user "Alice" removes the link from space "NewSpace" using root endpoint of the Graph API + And the HTTP status code should be "204" + When user "Alice" removes the link from space "NewSpace" using root endpoint of the Graph API + Then the HTTP status code should be "404" + @issue-7879 Scenario Outline: user tries to remove link share of project space owned by next user using root endpoint Given the administrator has assigned the role "Space Admin" to user "Alice" using the Graph API diff --git a/vendor/github.com/opencloud-eu/reva/v2/internal/grpc/services/gateway/usershareprovider.go b/vendor/github.com/opencloud-eu/reva/v2/internal/grpc/services/gateway/usershareprovider.go index 422752fac1..b042eeaf98 100644 --- a/vendor/github.com/opencloud-eu/reva/v2/internal/grpc/services/gateway/usershareprovider.go +++ b/vendor/github.com/opencloud-eu/reva/v2/internal/grpc/services/gateway/usershareprovider.go @@ -537,7 +537,13 @@ func (s *svc) removeShare(ctx context.Context, req *collaboration.RemoveShareReq return nil, errors.Wrap(err, "gateway: error calling GetShare") } - if getShareRes.Status.Code != rpc.Code_CODE_OK { + switch getShareRes.GetStatus().GetCode() { + case rpc.Code_CODE_OK: + case rpc.Code_CODE_NOT_FOUND: + return &collaboration.RemoveShareResponse{ + Status: getShareRes.GetStatus(), + }, nil + default: res := &collaboration.RemoveShareResponse{ Status: status.NewInternal(ctx, "error getting share when committing to the storage"), diff --git a/vendor/github.com/opencloud-eu/reva/v2/internal/grpc/services/publicshareprovider/publicshareprovider.go b/vendor/github.com/opencloud-eu/reva/v2/internal/grpc/services/publicshareprovider/publicshareprovider.go index 7aa7a90721..8d8b0c6a71 100644 --- a/vendor/github.com/opencloud-eu/reva/v2/internal/grpc/services/publicshareprovider/publicshareprovider.go +++ b/vendor/github.com/opencloud-eu/reva/v2/internal/grpc/services/publicshareprovider/publicshareprovider.go @@ -351,9 +351,16 @@ func (s *service) RemovePublicShare(ctx context.Context, req *link.RemovePublicS user := ctxpkg.ContextMustGetUser(ctx) ps, err := s.sm.GetPublicShare(ctx, user, req.GetRef(), false) if err != nil { + var st *rpc.Status + switch err.(type) { + case errtypes.IsNotFound: + st = status.NewNotFound(ctx, err.Error()) + default: + st = status.NewInternal(ctx, "error loading public share") + } return &link.RemovePublicShareResponse{ - Status: status.NewInternal(ctx, "error loading public share"), - }, err + Status: st, + }, nil } sRes, err := gatewayClient.Stat(ctx, &provider.StatRequest{Ref: &provider.Reference{ResourceId: ps.ResourceId}}) diff --git a/vendor/github.com/opencloud-eu/reva/v2/internal/grpc/services/usershareprovider/usershareprovider.go b/vendor/github.com/opencloud-eu/reva/v2/internal/grpc/services/usershareprovider/usershareprovider.go index 560cf9df31..c431c65eac 100644 --- a/vendor/github.com/opencloud-eu/reva/v2/internal/grpc/services/usershareprovider/usershareprovider.go +++ b/vendor/github.com/opencloud-eu/reva/v2/internal/grpc/services/usershareprovider/usershareprovider.go @@ -392,8 +392,15 @@ func (s *service) RemoveShare(ctx context.Context, req *collaboration.RemoveShar user := ctxpkg.ContextMustGetUser(ctx) share, err := s.sm.GetShare(ctx, req.Ref) if err != nil { + var st *rpc.Status + switch err.(type) { + case errtypes.IsNotFound: + st = status.NewNotFound(ctx, err.Error()) + default: + st = status.NewInternal(ctx, "error getting share") + } return &collaboration.RemoveShareResponse{ - Status: status.NewInternal(ctx, "error getting share"), + Status: st, }, nil } diff --git a/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/blobstore/blobstore.go b/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/blobstore/blobstore.go index 75f598c784..aa44d32bc8 100644 --- a/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/blobstore/blobstore.go +++ b/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/blobstore/blobstore.go @@ -143,6 +143,20 @@ func (bs *Blobstore) Upload(n *node.Node, source, copyTarget string) error { return fmt.Errorf("failed to set mtime on temp file '%s' - %v", tempName, err) } + // keep a handle on the blob before it moves to its final location. the handle stays valid + // across the rename, so the copy below needs neither the source file, which the rename above + // may have consumed, nor a second lookup of the final path + var blobFile *os.File + if copyTarget != "" { + blobFile, err = os.Open(tempName) + if err != nil { + return errors.Wrapf(err, "could not open temp file '%s' for reading", tempName) + } + defer func() { + _ = blobFile.Close() + }() + } + // atomically move the file to its final location, // on Windows systems (unsupported oc os) os.Rename is not atomic if err := os.Rename(tempName, n.InternalPath()); err != nil { @@ -155,14 +169,6 @@ func (bs *Blobstore) Upload(n *node.Node, source, copyTarget string) error { } // also "upload" the file to a local path, e.g., for keeping the "current" version of the file - sourceFile, err := os.Open(source) - if err != nil { - return errors.Wrapf(err, "could not open source file '%s' for reading", source) - } - defer func() { - _ = sourceFile.Close() - }() - if err := os.MkdirAll(filepath.Dir(copyTarget), 0700); err != nil { return err } @@ -175,7 +181,7 @@ func (bs *Blobstore) Upload(n *node.Node, source, copyTarget string) error { _ = copyFile.Close() }() - if err := copyWithPeriodicSync(copyFile, sourceFile); err != nil { + if err := copyWithPeriodicSync(copyFile, blobFile); err != nil { return errors.Wrapf(err, "could not write blob copy of '%s' to '%s'", n.InternalPath(), copyTarget) } diff --git a/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/tree/assimilation.go b/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/tree/assimilation.go index 2815dc07b2..8ce956506e 100644 --- a/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/tree/assimilation.go +++ b/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/fs/posix/tree/assimilation.go @@ -27,6 +27,7 @@ import ( "io/fs" "os" "path/filepath" + "strconv" "strings" "sync" "syscall" @@ -537,7 +538,7 @@ func (t *Tree) assimilate(item scanItem) error { if fi.IsDir() { // if it was moved and it is a directory we need to propagate the move go func() { - if err := t.WarmupIDCache(item.Path, false, true); err != nil { + if err := t.WarmupIDCache(item.Path, false, false); err != nil { t.log.Error().Err(err).Str("path", item.Path).Msg("could not warmup id cache") } }() @@ -920,6 +921,12 @@ func (t *Tree) WarmupIDCache(root string, assimilate, onlyDirty bool) error { } sizes := make(map[string]int64) + addToParents := func(path string, size int64) { + for dir := path; dir != root; { + dir = filepath.Clean(filepath.Dir(dir)) + sizes[dir] += size + } + } err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error { if err != nil { return err @@ -948,22 +955,24 @@ func (t *Tree) WarmupIDCache(root string, assimilate, onlyDirty bool) error { // calculate tree sizes if !info.IsDir() { - dir := path - for dir != root { - dir = filepath.Clean(filepath.Dir(dir)) - sizes[dir] += info.Size() - } + addToParents(path, info.Size()) } else { - sizes[path] += 0 // Make sure to set the size to 0 for empty directories if onlyDirty { dirty, err := t.isDirty(path) if err != nil { return err } if !dirty { - return filepath.SkipDir + // the stored tree size of a clean directory is still valid. Count it for the + // parents instead of overwriting it with the size of the files we skip. + if size, ok := t.storedTreeSize(path); ok { + addToParents(path, size) + return filepath.SkipDir + } + // without a valid stored tree size, walk the directory to calculate it } } + sizes[path] += 0 // Make sure to set the size to 0 for empty directories } nodeSpaceID, id, _, _, err := t.lookup.MetadataBackend().IdentifyPath(context.Background(), path) @@ -1093,6 +1102,15 @@ func (t *Tree) setDirty(path string, dirty bool) error { return xattr.Set(path, dirtyFlag(), []byte(fmt.Sprintf("%t", dirty))) } +func (t *Tree) storedTreeSize(path string) (int64, bool) { + b, err := xattr.Get(path, prefixes.TreesizeAttr) + if err != nil { + return 0, false + } + size, err := strconv.ParseInt(string(b), 10, 64) + return size, err == nil && size >= 0 +} + func (t *Tree) isDirty(path string) (bool, error) { dirtyAttr, err := xattr.Get(path, dirtyFlag()) if err != nil { diff --git a/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/spaces.go b/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/spaces.go index 2421c3c074..c6effc17ab 100644 --- a/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/spaces.go +++ b/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/spaces.go @@ -1232,7 +1232,8 @@ func canDeleteSpace(ctx context.Context, spaceID string, typ string, purge bool, } // space managers are allowed to disable their project spaces - if rp, err := p.AssemblePermissions(ctx, n); err == nil && !purge && permissions.IsManager(rp) { + rp, err := p.AssemblePermissions(ctx, n) + if err == nil && !purge && permissions.IsManager(rp) { return nil } @@ -1246,5 +1247,10 @@ func canDeleteSpace(ctx context.Context, spaceID string, typ string, purge bool, return nil } + // users without any grant on an active space must not learn that it exists + if err == nil && !rp.GetStat() && !n.IsDisabled(ctx) { + return errtypes.NotFound(spaceID) + } + return errtypes.PermissionDenied(fmt.Sprintf("user is not allowed to delete space %s", n.GetID())) } diff --git a/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/upload/upload.go b/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/upload/upload.go index e67cfcd031..a0caf51c57 100644 --- a/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/upload/upload.go +++ b/vendor/github.com/opencloud-eu/reva/v2/pkg/storage/pkg/decomposedfs/upload/upload.go @@ -256,7 +256,7 @@ func (session *DecomposedFsSession) FinishUploadDecomposed(ctx context.Context) if !session.store.async || session.info.Size == 0 { // handle postprocessing synchronously err = session.Finalize(ctx) - session.Cleanup(err != nil, true, true, true) + session.Cleanup(err != nil, err == nil, true, true) if err != nil { log.Error().Err(err).Msg("failed to upload") return err diff --git a/vendor/modules.txt b/vendor/modules.txt index 8bbc2ed722..ce2f09511c 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1360,7 +1360,7 @@ github.com/opencloud-eu/icap-client # github.com/opencloud-eu/libre-graph-api-go v1.0.9-0.20261008090127-e04fc3d3e458 ## explicit; go 1.23 github.com/opencloud-eu/libre-graph-api-go -# github.com/opencloud-eu/reva/v2 v2.51.1-0.20261009143138-36d43ce34b87 +# github.com/opencloud-eu/reva/v2 v2.51.1-0.20261014072417-be32dce83442 ## explicit; go 1.26.0 github.com/opencloud-eu/reva/v2/cmd/revad/internal/grace github.com/opencloud-eu/reva/v2/cmd/revad/runtime