diff --git a/changelog/unreleased/bump-reva.md b/changelog/unreleased/bump-reva.md new file mode 100644 index 0000000000..06ea1e4626 --- /dev/null +++ b/changelog/unreleased/bump-reva.md @@ -0,0 +1,5 @@ +Bugfix: Bump Reva + +bumps reva version + +https://github.com/owncloud/ocis/pull/10539 diff --git a/go.mod b/go.mod index fc4461eab3..45a14aced3 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,7 @@ require ( github.com/cenkalti/backoff v2.2.1+incompatible github.com/coreos/go-oidc/v3 v3.11.0 github.com/cs3org/go-cs3apis v0.0.0-20241105092511-3ad35d174fc1 - github.com/cs3org/reva/v2 v2.26.4 + github.com/cs3org/reva/v2 v2.26.5-0.20241111162950-e77dd61e7edb github.com/davidbyttow/govips/v2 v2.15.0 github.com/dhowden/tag v0.0.0-20240417053706-3d75831295e8 github.com/dutchcoders/go-clamd v0.0.0-20170520113014-b970184f4d9e diff --git a/go.sum b/go.sum index 88f302e3ed..b23ce59e8a 100644 --- a/go.sum +++ b/go.sum @@ -255,8 +255,8 @@ github.com/crewjam/saml v0.4.14 h1:g9FBNx62osKusnFzs3QTN5L9CVA/Egfgm+stJShzw/c= github.com/crewjam/saml v0.4.14/go.mod h1:UVSZCf18jJkk6GpWNVqcyQJMD5HsRugBPf4I1nl2mME= github.com/cs3org/go-cs3apis v0.0.0-20241105092511-3ad35d174fc1 h1:RU6LT6mkD16xZs011+8foU7T3LrPvTTSWeTQ9OgfhkA= github.com/cs3org/go-cs3apis v0.0.0-20241105092511-3ad35d174fc1/go.mod h1:DedpcqXl193qF/08Y04IO0PpxyyMu8+GrkD6kWK2MEQ= -github.com/cs3org/reva/v2 v2.26.4 h1:wUmNSkXglIHrn+yxwJtHDvlSzxadFPANENGnwmG+5wI= -github.com/cs3org/reva/v2 v2.26.4/go.mod h1:KP0Zomt3dNIr/kU2M1mXzTIVFOtxBVS4qmBDMRCfrOQ= +github.com/cs3org/reva/v2 v2.26.5-0.20241111162950-e77dd61e7edb h1:owRv9x5GlKKdqCCM70kZKCsLAcDkFPkyOb129Jmklt0= +github.com/cs3org/reva/v2 v2.26.5-0.20241111162950-e77dd61e7edb/go.mod h1:KP0Zomt3dNIr/kU2M1mXzTIVFOtxBVS4qmBDMRCfrOQ= github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= diff --git a/vendor/github.com/cs3org/reva/v2/pkg/storage/fs/posix/tree/assimilation.go b/vendor/github.com/cs3org/reva/v2/pkg/storage/fs/posix/tree/assimilation.go index eca850ff4a..687eb5ca47 100644 --- a/vendor/github.com/cs3org/reva/v2/pkg/storage/fs/posix/tree/assimilation.go +++ b/vendor/github.com/cs3org/reva/v2/pkg/storage/fs/posix/tree/assimilation.go @@ -59,6 +59,7 @@ const ( ActionUpdate ActionMove ActionDelete + ActionMoveFrom ) type queueItem struct { @@ -160,14 +161,14 @@ func (t *Tree) workScanQueue() { } // Scan scans the given path and updates the id chache -func (t *Tree) Scan(path string, action EventAction, isDir bool, recurse bool) error { +func (t *Tree) Scan(path string, action EventAction, isDir bool) error { // cases: switch action { case ActionCreate: if !isDir { // 1. New file (could be emitted as part of a new directory) // -> assimilate file - // -> scan parent directory recursively + // -> scan parent directory recursively to update tree size and catch nodes that weren't covered by an event if !t.scanDebouncer.InProgress(filepath.Dir(path)) { t.scanDebouncer.Debounce(scanItem{ Path: path, @@ -216,8 +217,24 @@ func (t *Tree) Scan(path string, action EventAction, isDir bool, recurse bool) e Recurse: isDir, }) + case ActionMoveFrom: + // 6. file/directory moved out of the watched directory + // -> update directory + if err := t.setDirty(filepath.Dir(path), true); err != nil { + return err + } + + go func() { _ = t.WarmupIDCache(filepath.Dir(path), false, true) }() + case ActionDelete: _ = t.HandleFileDelete(path) + // 7. Deleted file or directory + // -> update parent and all children + t.scanDebouncer.Debounce(scanItem{ + Path: filepath.Dir(path), + ForceRescan: true, + Recurse: true, + }) } return nil @@ -593,6 +610,7 @@ func (t *Tree) WarmupIDCache(root string, assimilate, onlyDirty bool) error { if !dirty { return filepath.SkipDir } + sizes[path] += 0 // Make sure to set the size to 0 for empty directories } attribs, err := t.lookup.MetadataBackend().All(context.Background(), path) diff --git a/vendor/github.com/cs3org/reva/v2/pkg/storage/fs/posix/tree/gpfsfilauditloggingwatcher.go b/vendor/github.com/cs3org/reva/v2/pkg/storage/fs/posix/tree/gpfsfilauditloggingwatcher.go index 5c8d8a201f..ead3cf398f 100644 --- a/vendor/github.com/cs3org/reva/v2/pkg/storage/fs/posix/tree/gpfsfilauditloggingwatcher.go +++ b/vendor/github.com/cs3org/reva/v2/pkg/storage/fs/posix/tree/gpfsfilauditloggingwatcher.go @@ -1,3 +1,21 @@ +// Copyright 2018-2024 CERN +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// In applying this license, CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + package tree import ( @@ -64,15 +82,15 @@ start: } switch ev.Event { case "CREATE": - go func() { _ = w.tree.Scan(ev.Path, ActionCreate, false, false) }() + go func() { _ = w.tree.Scan(ev.Path, ActionCreate, false) }() case "CLOSE": bytesWritten, err := strconv.Atoi(ev.BytesWritten) if err == nil && bytesWritten > 0 { - go func() { _ = w.tree.Scan(ev.Path, ActionUpdate, false, true) }() + go func() { _ = w.tree.Scan(ev.Path, ActionUpdate, false) }() } case "RENAME": go func() { - _ = w.tree.Scan(ev.Path, ActionMove, false, true) + _ = w.tree.Scan(ev.Path, ActionMove, false) _ = w.tree.WarmupIDCache(ev.Path, false, false) }() } diff --git a/vendor/github.com/cs3org/reva/v2/pkg/storage/fs/posix/tree/gpfswatchfolderwatcher.go b/vendor/github.com/cs3org/reva/v2/pkg/storage/fs/posix/tree/gpfswatchfolderwatcher.go index e206e27284..5a0fb6a4bd 100644 --- a/vendor/github.com/cs3org/reva/v2/pkg/storage/fs/posix/tree/gpfswatchfolderwatcher.go +++ b/vendor/github.com/cs3org/reva/v2/pkg/storage/fs/posix/tree/gpfswatchfolderwatcher.go @@ -1,3 +1,21 @@ +// Copyright 2018-2024 CERN +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// In applying this license, CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + package tree import ( @@ -29,13 +47,13 @@ func (w *GpfsWatchFolderWatcher) Watch(topic string) { Topic: topic, }) - lwev := &lwe{} for { m, err := r.ReadMessage(context.Background()) if err != nil { break } + lwev := &lwe{} err = json.Unmarshal(m.Value, lwev) if err != nil { continue @@ -45,22 +63,28 @@ func (w *GpfsWatchFolderWatcher) Watch(topic string) { continue } - isDir := strings.Contains(lwev.Event, "IN_ISDIR") + go func() { + isDir := strings.Contains(lwev.Event, "IN_ISDIR") - switch { - case strings.Contains(lwev.Event, "IN_CREATE"): - go func() { _ = w.tree.Scan(lwev.Path, ActionCreate, isDir, false) }() + switch { + case strings.Contains(lwev.Event, "IN_DELETE"): + _ = w.tree.Scan(lwev.Path, ActionDelete, isDir) - case strings.Contains(lwev.Event, "IN_CLOSE_WRITE"): - bytesWritten, err := strconv.Atoi(lwev.BytesWritten) - if err == nil && bytesWritten > 0 { - go func() { _ = w.tree.Scan(lwev.Path, ActionUpdate, isDir, true) }() + case strings.Contains(lwev.Event, "IN_MOVE_FROM"): + _ = w.tree.Scan(lwev.Path, ActionMoveFrom, isDir) + + case strings.Contains(lwev.Event, "IN_CREATE"): + _ = w.tree.Scan(lwev.Path, ActionCreate, isDir) + + case strings.Contains(lwev.Event, "IN_CLOSE_WRITE"): + bytesWritten, err := strconv.Atoi(lwev.BytesWritten) + if err == nil && bytesWritten > 0 { + _ = w.tree.Scan(lwev.Path, ActionUpdate, isDir) + } + case strings.Contains(lwev.Event, "IN_MOVED_TO"): + _ = w.tree.Scan(lwev.Path, ActionMove, isDir) } - case strings.Contains(lwev.Event, "IN_MOVED_TO"): - go func() { - _ = w.tree.Scan(lwev.Path, ActionMove, isDir, true) - }() - } + }() } if err := r.Close(); err != nil { log.Fatal("failed to close reader:", err) diff --git a/vendor/github.com/cs3org/reva/v2/pkg/storage/fs/posix/tree/inotifywatcher.go b/vendor/github.com/cs3org/reva/v2/pkg/storage/fs/posix/tree/inotifywatcher.go index 2858b851bc..54b7157e0f 100644 --- a/vendor/github.com/cs3org/reva/v2/pkg/storage/fs/posix/tree/inotifywatcher.go +++ b/vendor/github.com/cs3org/reva/v2/pkg/storage/fs/posix/tree/inotifywatcher.go @@ -1,3 +1,21 @@ +// Copyright 2018-2024 CERN +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// In applying this license, CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + package tree import ( @@ -30,6 +48,7 @@ func (iw *InotifyWatcher) Watch(path string) { Events: []inotifywaitgo.EVENT{ inotifywaitgo.CREATE, inotifywaitgo.MOVED_TO, + inotifywaitgo.MOVED_FROM, inotifywaitgo.CLOSE_WRITE, inotifywaitgo.DELETE, }, @@ -45,18 +64,18 @@ func (iw *InotifyWatcher) Watch(path string) { if isLockFile(event.Filename) || isTrash(event.Filename) || iw.tree.isUpload(event.Filename) { continue } - switch e { - case inotifywaitgo.DELETE: - go func() { _ = iw.tree.HandleFileDelete(event.Filename) }() - case inotifywaitgo.CREATE: - go func() { _ = iw.tree.Scan(event.Filename, ActionCreate, event.IsDir, false) }() - case inotifywaitgo.MOVED_TO: - go func() { - _ = iw.tree.Scan(event.Filename, ActionMove, event.IsDir, true) - }() - case inotifywaitgo.CLOSE_WRITE: - go func() { _ = iw.tree.Scan(event.Filename, ActionUpdate, event.IsDir, true) }() - } + go func() { + switch e { + case inotifywaitgo.DELETE: + _ = iw.tree.Scan(event.Filename, ActionDelete, event.IsDir) + case inotifywaitgo.MOVED_FROM: + _ = iw.tree.Scan(event.Filename, ActionMoveFrom, event.IsDir) + case inotifywaitgo.CREATE, inotifywaitgo.MOVED_TO: + _ = iw.tree.Scan(event.Filename, ActionCreate, event.IsDir) + case inotifywaitgo.CLOSE_WRITE: + _ = iw.tree.Scan(event.Filename, ActionUpdate, event.IsDir) + } + }() } case err := <-errors: diff --git a/vendor/github.com/cs3org/reva/v2/pkg/storage/fs/posix/tree/tree.go b/vendor/github.com/cs3org/reva/v2/pkg/storage/fs/posix/tree/tree.go index f41ab1dfb9..2ba94a88a7 100644 --- a/vendor/github.com/cs3org/reva/v2/pkg/storage/fs/posix/tree/tree.go +++ b/vendor/github.com/cs3org/reva/v2/pkg/storage/fs/posix/tree/tree.go @@ -310,6 +310,12 @@ func (t *Tree) Move(ctx context.Context, oldNode *node.Node, newNode *node.Node) return errors.Wrap(err, "Decomposedfs: could not move child") } + // update the id cache + if newNode.ID == "" { + newNode.ID = oldNode.ID + } + _ = t.lookup.(*lookup.Lookup).CacheID(ctx, newNode.SpaceID, newNode.ID, filepath.Join(newNode.ParentPath(), newNode.Name)) + // rename the lock (if it exists) if _, err := os.Stat(oldNode.LockFilePath()); err == nil { err = os.Rename( @@ -321,11 +327,6 @@ func (t *Tree) Move(ctx context.Context, oldNode *node.Node, newNode *node.Node) } } - // update the id cache - if newNode.ID == "" { - newNode.ID = oldNode.ID - } - _ = t.lookup.(*lookup.Lookup).CacheID(ctx, newNode.SpaceID, newNode.ID, filepath.Join(newNode.ParentPath(), newNode.Name)) // update id cache for the moved subtree. if oldNode.IsDir(ctx) { err = t.WarmupIDCache(filepath.Join(newNode.ParentPath(), newNode.Name), false, false) @@ -334,11 +335,23 @@ func (t *Tree) Move(ctx context.Context, oldNode *node.Node, newNode *node.Node) } } - err = t.Propagate(ctx, oldNode, 0) + // the size diff is the current treesize or blobsize of the old/source node + var sizeDiff int64 + if oldNode.IsDir(ctx) { + treeSize, err := oldNode.GetTreeSize(ctx) + if err != nil { + return err + } + sizeDiff = int64(treeSize) + } else { + sizeDiff = oldNode.Blobsize + } + + err = t.Propagate(ctx, oldNode, -sizeDiff) if err != nil { return errors.Wrap(err, "Decomposedfs: Move: could not propagate old node") } - err = t.Propagate(ctx, newNode, 0) + err = t.Propagate(ctx, newNode, sizeDiff) if err != nil { return errors.Wrap(err, "Decomposedfs: Move: could not propagate new node") } diff --git a/vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/tree/propagator/sync.go b/vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/tree/propagator/sync.go index 5043d19c90..d32f7de084 100644 --- a/vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/tree/propagator/sync.go +++ b/vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/tree/propagator/sync.go @@ -30,6 +30,7 @@ import ( "github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/metadata/prefixes" "github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/node" "github.com/rogpeppe/go-internal/lockedfile" + "github.com/rs/zerolog" ) // SyncPropagator implements synchronous treetime & treesize propagation @@ -72,137 +73,137 @@ func (p SyncPropagator) Propagate(ctx context.Context, n *node.Node, sizeDiff in sTime := time.Now().UTC() // we loop until we reach the root - var err error - for err == nil && n.ID != root.ID { - sublog.Debug().Msg("propagating") + var ( + err error + stop bool + ) - attrs := node.Attributes{} - - var f *lockedfile.File - // lock parent before reading treesize or tree time - - _, subspan := tracer.Start(ctx, "lockedfile.OpenFile") - parentFilename := p.lookup.MetadataBackend().LockfilePath(n.ParentPath()) - f, err = lockedfile.OpenFile(parentFilename, os.O_RDWR|os.O_CREATE, 0600) - subspan.End() - if err != nil { - sublog.Error().Err(err). - Str("parent filename", parentFilename). - Msg("Propagation failed. Could not open metadata for parent with lock.") - return err - } - // always log error if closing node fails - defer func() { - // ignore already closed error - cerr := f.Close() - if err == nil && cerr != nil && !errors.Is(cerr, os.ErrClosed) { - err = cerr // only overwrite err with en error from close if the former was nil - } - _ = os.Remove(f.Name()) - }() - - if n, err = n.Parent(ctx); err != nil { - sublog.Error().Err(err). - Msg("Propagation failed. Could not read parent node.") - return err - } - - if !n.HasPropagation(ctx) { - sublog.Debug().Str("attr", prefixes.PropagationAttr).Msg("propagation attribute not set or unreadable, not propagating") - // if the attribute is not set treat it as false / none / no propagation - return nil - } - - sublog = sublog.With().Str("spaceid", n.SpaceID).Str("nodeid", n.ID).Logger() - - if p.treeTimeAccounting { - // update the parent tree time if it is older than the nodes mtime - updateSyncTime := false - - var tmTime time.Time - tmTime, err = n.GetTMTime(ctx) - switch { - case err != nil: - // missing attribute, or invalid format, overwrite - sublog.Debug().Err(err). - Msg("could not read tmtime attribute, overwriting") - updateSyncTime = true - case tmTime.Before(sTime): - sublog.Debug(). - Time("tmtime", tmTime). - Time("stime", sTime). - Msg("parent tmtime is older than node mtime, updating") - updateSyncTime = true - default: - sublog.Debug(). - Time("tmtime", tmTime). - Time("stime", sTime). - Dur("delta", sTime.Sub(tmTime)). - Msg("parent tmtime is younger than node mtime, not updating") - } - - if updateSyncTime { - // update the tree time of the parent node - attrs.SetString(prefixes.TreeMTimeAttr, sTime.UTC().Format(time.RFC3339Nano)) - } - - attrs.SetString(prefixes.TmpEtagAttr, "") - } - - // size accounting - if p.treeSizeAccounting && sizeDiff != 0 { - var newSize uint64 - - // read treesize - treeSize, err := n.GetTreeSize(ctx) - switch { - case metadata.IsAttrUnset(err): - // fallback to calculating the treesize - sublog.Warn().Msg("treesize attribute unset, falling back to calculating the treesize") - newSize, err = calculateTreeSize(ctx, p.lookup, n.InternalPath()) - if err != nil { - return err - } - case err != nil: - sublog.Error().Err(err). - Msg("Faild to propagate treesize change. Error when reading the treesize attribute from parent") - return err - case sizeDiff > 0: - newSize = treeSize + uint64(sizeDiff) - case uint64(-sizeDiff) > treeSize: - // The sizeDiff is larger than the current treesize. Which would result in - // a negative new treesize. Something must have gone wrong with the accounting. - // Reset the current treesize to 0. - sublog.Error().Uint64("treeSize", treeSize).Int64("sizeDiff", sizeDiff). - Msg("Error when updating treesize of parent node. Updated treesize < 0. Reestting to 0") - newSize = 0 - default: - newSize = treeSize - uint64(-sizeDiff) - } - - // update the tree size of the node - attrs.SetString(prefixes.TreesizeAttr, strconv.FormatUint(newSize, 10)) - sublog.Debug().Uint64("newSize", newSize).Msg("updated treesize of parent node") - } - - if err = n.SetXattrsWithContext(ctx, attrs, false); err != nil { - sublog.Error().Err(err).Msg("Failed to update extend attributes of parent node") - return err - } - - // Release node lock early, ignore already closed error - _, subspan = tracer.Start(ctx, "f.Close") - cerr := f.Close() - subspan.End() - if cerr != nil && !errors.Is(cerr, os.ErrClosed) { - sublog.Error().Err(cerr).Msg("Failed to close parent node and release lock") - return cerr - } + for err == nil && !stop && n.ID != root.ID { + n, stop, err = p.propagateItem(ctx, n, sTime, sizeDiff, sublog) } + if err != nil { sublog.Error().Err(err).Msg("error propagating") return err } return nil - +} + +func (p SyncPropagator) propagateItem(ctx context.Context, n *node.Node, sTime time.Time, sizeDiff int64, log zerolog.Logger) (*node.Node, bool, error) { + log.Debug().Msg("propagating") + + attrs := node.Attributes{} + + var f *lockedfile.File + // lock parent before reading treesize or tree time + + _, subspan := tracer.Start(ctx, "lockedfile.OpenFile") + parentFilename := p.lookup.MetadataBackend().LockfilePath(n.ParentPath()) + f, err := lockedfile.OpenFile(parentFilename, os.O_RDWR|os.O_CREATE, 0600) + subspan.End() + if err != nil { + log.Error().Err(err). + Str("parent filename", parentFilename). + Msg("Propagation failed. Could not open metadata for parent with lock.") + return nil, true, err + } + // always log error if closing node fails + defer func() { + // ignore already closed error + cerr := f.Close() + if err == nil && cerr != nil && !errors.Is(cerr, os.ErrClosed) { + err = cerr // only overwrite err with en error from close if the former was nil + } + }() + + if n, err = n.Parent(ctx); err != nil { + log.Error().Err(err). + Msg("Propagation failed. Could not read parent node.") + return n, true, err + } + + if !n.HasPropagation(ctx) { + log.Debug().Str("attr", prefixes.PropagationAttr).Msg("propagation attribute not set or unreadable, not propagating") + // if the attribute is not set treat it as false / none / no propagation + return n, true, nil + } + + log = log.With().Str("spaceid", n.SpaceID).Str("nodeid", n.ID).Logger() + + if p.treeTimeAccounting { + // update the parent tree time if it is older than the nodes mtime + updateSyncTime := false + + var tmTime time.Time + tmTime, err = n.GetTMTime(ctx) + switch { + case err != nil: + // missing attribute, or invalid format, overwrite + log.Debug().Err(err). + Msg("could not read tmtime attribute, overwriting") + updateSyncTime = true + case tmTime.Before(sTime): + log.Debug(). + Time("tmtime", tmTime). + Time("stime", sTime). + Msg("parent tmtime is older than node mtime, updating") + updateSyncTime = true + default: + log.Debug(). + Time("tmtime", tmTime). + Time("stime", sTime). + Dur("delta", sTime.Sub(tmTime)). + Msg("parent tmtime is younger than node mtime, not updating") + } + + if updateSyncTime { + // update the tree time of the parent node + attrs.SetString(prefixes.TreeMTimeAttr, sTime.UTC().Format(time.RFC3339Nano)) + } + + attrs.SetString(prefixes.TmpEtagAttr, "") + } + + // size accounting + if p.treeSizeAccounting && sizeDiff != 0 { + var newSize uint64 + + // read treesize + treeSize, err := n.GetTreeSize(ctx) + switch { + case metadata.IsAttrUnset(err): + // fallback to calculating the treesize + log.Warn().Msg("treesize attribute unset, falling back to calculating the treesize") + newSize, err = calculateTreeSize(ctx, p.lookup, n.InternalPath()) + if err != nil { + return n, true, err + } + case err != nil: + log.Error().Err(err). + Msg("Faild to propagate treesize change. Error when reading the treesize attribute from parent") + return n, true, err + case sizeDiff > 0: + newSize = treeSize + uint64(sizeDiff) + case uint64(-sizeDiff) > treeSize: + // The sizeDiff is larger than the current treesize. Which would result in + // a negative new treesize. Something must have gone wrong with the accounting. + // Reset the current treesize to 0. + log.Error().Uint64("treeSize", treeSize).Int64("sizeDiff", sizeDiff). + Msg("Error when updating treesize of parent node. Updated treesize < 0. Reestting to 0") + newSize = 0 + default: + newSize = treeSize - uint64(-sizeDiff) + } + + // update the tree size of the node + attrs.SetString(prefixes.TreesizeAttr, strconv.FormatUint(newSize, 10)) + log.Debug().Uint64("newSize", newSize).Msg("updated treesize of parent node") + } + + if err = n.SetXattrsWithContext(ctx, attrs, false); err != nil { + log.Error().Err(err).Msg("Failed to update extend attributes of parent node") + return n, true, err + } + + return n, false, nil } diff --git a/vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/upload.go b/vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/upload.go index d0b84f6a79..eba3c91808 100644 --- a/vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/upload.go +++ b/vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/upload.go @@ -26,10 +26,11 @@ import ( "strings" "time" + provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" "github.com/google/uuid" + "github.com/pkg/errors" tusd "github.com/tus/tusd/v2/pkg/handler" - provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" "github.com/cs3org/reva/v2/pkg/appctx" ctxpkg "github.com/cs3org/reva/v2/pkg/ctx" "github.com/cs3org/reva/v2/pkg/errtypes" @@ -40,7 +41,6 @@ import ( "github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/upload" "github.com/cs3org/reva/v2/pkg/storagespace" "github.com/cs3org/reva/v2/pkg/utils" - "github.com/pkg/errors" ) // Upload uploads data to the given resource @@ -90,7 +90,7 @@ func (fs *Decomposedfs) Upload(ctx context.Context, req storage.UploadRequest, u } } - if err := session.FinishUpload(ctx); err != nil { + if err := session.FinishUploadDecomposed(ctx); err != nil { return &provider.ResourceInfo{}, err } @@ -321,7 +321,7 @@ func (fs *Decomposedfs) InitiateUpload(ctx context.Context, ref *provider.Refere if uploadLength == 0 { // Directly finish this upload - err = session.FinishUpload(ctx) + err = session.FinishUploadDecomposed(ctx) if err != nil { return nil, err } diff --git a/vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/upload/upload.go b/vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/upload/upload.go index 427af92dbc..f460c526ed 100644 --- a/vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/upload/upload.go +++ b/vendor/github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/upload/upload.go @@ -33,6 +33,12 @@ import ( userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" + "github.com/golang-jwt/jwt" + "github.com/pkg/errors" + tusd "github.com/tus/tusd/v2/pkg/handler" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/trace" + "github.com/cs3org/reva/v2/pkg/appctx" ctxpkg "github.com/cs3org/reva/v2/pkg/ctx" "github.com/cs3org/reva/v2/pkg/errtypes" @@ -41,11 +47,6 @@ import ( "github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/metadata/prefixes" "github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/node" "github.com/cs3org/reva/v2/pkg/utils" - "github.com/golang-jwt/jwt" - "github.com/pkg/errors" - tusd "github.com/tus/tusd/v2/pkg/handler" - "go.opentelemetry.io/otel" - "go.opentelemetry.io/otel/trace" ) var ( @@ -106,7 +107,25 @@ func (session *OcisSession) GetReader(ctx context.Context) (io.ReadCloser, error } // FinishUpload finishes an upload and moves the file to the internal destination +// implements tusd.DataStore interface +// returns tusd errors func (session *OcisSession) FinishUpload(ctx context.Context) error { + err := session.FinishUploadDecomposed(ctx) + + // we need to return a tusd error here to make the tusd handler return the correct status code + switch err.(type) { + case errtypes.AlreadyExists: + return tusd.NewError("ERR_ALREADY_EXISTS", err.Error(), http.StatusConflict) + case errtypes.Aborted: + return tusd.NewError("ERR_PRECONDITION_FAILED", err.Error(), http.StatusPreconditionFailed) + default: + return err + } +} + +// FinishUploadDecomposed finishes an upload and moves the file to the internal destination +// retures errtypes errors +func (session *OcisSession) FinishUploadDecomposed(ctx context.Context) error { ctx, span := tracer.Start(session.Context(ctx), "FinishUpload") defer span.End() log := appctx.GetLogger(ctx) @@ -167,16 +186,7 @@ func (session *OcisSession) FinishUpload(ctx context.Context) error { n, err := session.store.CreateNodeForUpload(session, attrs) if err != nil { - session.store.Cleanup(ctx, session, true, false, false) - // we need to return a tusd error here to make the tusd handler return the correct status code - switch err.(type) { - case errtypes.AlreadyExists: - return ErrAlreadyExists - case errtypes.Aborted: - return tusd.NewError("ERR_PRECONDITION_FAILED", err.Error(), http.StatusPreconditionFailed) - default: - return err - } + return err } // increase the processing counter for every started processing // will be decreased in Cleanup() diff --git a/vendor/modules.txt b/vendor/modules.txt index 0511c7f004..d14e7b085b 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -367,7 +367,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.26.4 +# github.com/cs3org/reva/v2 v2.26.5-0.20241111162950-e77dd61e7edb ## explicit; go 1.22.0 github.com/cs3org/reva/v2/cmd/revad/internal/grace github.com/cs3org/reva/v2/cmd/revad/runtime