Merge pull request #9556 from owncloud/update-reva

[full-ci] chore: bump reva to latest edge
This commit is contained in:
Michael Barz
2024-07-08 14:47:48 +02:00
committed by GitHub
16 changed files with 392 additions and 60 deletions
+10 -2
View File
@@ -1,5 +1,13 @@
Enhancement: Bump reva
Enhancement: Bump reva to v2.21.0
bumps reva version
* Bugfix [cs3org/reva#4740](https://github.com/cs3org/reva/pull/4740): Disallow reserved filenames
* Bugfix [cs3org/reva#4748](https://github.com/cs3org/reva/pull/4748): Quotes in dav Content-Disposition header
* Bugfix [cs3org/reva#4750](https://github.com/cs3org/reva/pull/4750): Validate a space path
* Enhancement [cs3org/reva#4737](https://github.com/cs3org/reva/pull/4737): Add the backchannel logout event
* Enhancement [cs3org/reva#4749](https://github.com/cs3org/reva/pull/4749): DAV error codes
* Enhancement [cs3org/reva#4742](https://github.com/cs3org/reva/pull/4742): Expose disable-versioning configuration option
* Enhancement [cs3org/reva#4739](https://github.com/cs3org/reva/pull/4739): Improve posixfs storage driver
* Enhancement [cs3org/reva#4738](https://github.com/cs3org/reva/pull/4738): Add GetServiceUserToken() method to utils pkg
https://github.com/owncloud/ocis/pull/9556
https://github.com/owncloud/ocis/pull/9473
+1 -1
View File
@@ -15,7 +15,7 @@ require (
github.com/cenkalti/backoff v2.2.1+incompatible
github.com/coreos/go-oidc/v3 v3.10.0
github.com/cs3org/go-cs3apis v0.0.0-20231023073225-7748710e0781
github.com/cs3org/reva/v2 v2.20.1-0.20240705133657-2b682c603c75
github.com/cs3org/reva/v2 v2.21.0
github.com/dhowden/tag v0.0.0-20230630033851-978a0926ee25
github.com/dutchcoders/go-clamd v0.0.0-20170520113014-b970184f4d9e
github.com/egirna/icap-client v0.1.1
+2 -2
View File
@@ -1024,8 +1024,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-20231023073225-7748710e0781 h1:BUdwkIlf8IS2FasrrPg8gGPHQPOrQ18MS1Oew2tmGtY=
github.com/cs3org/go-cs3apis v0.0.0-20231023073225-7748710e0781/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY=
github.com/cs3org/reva/v2 v2.20.1-0.20240705133657-2b682c603c75 h1:GdjSpSzDdH0qwamzJCwf3hCoveVB5IIWmt2l79LKWTA=
github.com/cs3org/reva/v2 v2.20.1-0.20240705133657-2b682c603c75/go.mod h1:Rb2XnhpGKnH7k6WBFZlMygbyBxW6ma09Z4Uk+ro0v+A=
github.com/cs3org/reva/v2 v2.21.0 h1:TLmWaU4BTIsi2FQtB8SxMKDT46ql28Do1Vc7IVWSAsE=
github.com/cs3org/reva/v2 v2.21.0/go.mod h1:Rb2XnhpGKnH7k6WBFZlMygbyBxW6ma09Z4Uk+ro0v+A=
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=
@@ -1276,7 +1276,10 @@ func getFS(c *config) (storage.FS, error) {
}
if f, ok := registry.NewFuncs[c.Driver]; ok {
return f(c.Drivers[c.Driver], evstream)
driverConf := c.Drivers[c.Driver]
driverConf["mount_id"] = c.MountID // pass the mount id to the driver
return f(driverConf, evstream)
}
return nil, errtypes.NotFound("driver not found: " + c.Driver)
+18 -2
View File
@@ -55,7 +55,14 @@ func init() {
// IDCache is a cache for node ids
type IDCache interface {
Get(ctx context.Context, spaceID, nodeID string) (string, bool)
GetByPath(ctx context.Context, path string) (string, string, bool)
Set(ctx context.Context, spaceID, nodeID, val string) error
Delete(ctx context.Context, spaceID, nodeID string) error
DeleteByPath(ctx context.Context, path string) error
DeletePath(ctx context.Context, path string) error
}
// Lookup implements transformations from filepath to node and back
@@ -79,16 +86,25 @@ func New(b metadata.Backend, um usermapper.Mapper, o *options.Options) *Lookup {
return lu
}
// CacheID caches the id for the given space and node id
// CacheID caches the path for the given space and node id
func (lu *Lookup) CacheID(ctx context.Context, spaceID, nodeID, val string) error {
return lu.IDCache.Set(ctx, spaceID, nodeID, val)
}
// GetCachedID returns the cached id for the given space and node id
// GetCachedID returns the cached path for the given space and node id
func (lu *Lookup) GetCachedID(ctx context.Context, spaceID, nodeID string) (string, bool) {
return lu.IDCache.Get(ctx, spaceID, nodeID)
}
// IDsForPath returns the space and opaque id for the given path
func (lu *Lookup) IDsForPath(ctx context.Context, path string) (string, string, error) {
spaceID, nodeID, ok := lu.IDCache.GetByPath(ctx, path)
if !ok {
return "", "", fmt.Errorf("path %s not found in cache", path)
}
return spaceID, nodeID, nil
}
// NodeFromPath returns the node for the given path
func (lu *Lookup) NodeIDFromParentAndName(ctx context.Context, parent *node.Node, name string) (string, error) {
id, err := lu.metadataBackend.Get(ctx, filepath.Join(parent.InternalPath(), name), prefixes.IDAttr)
@@ -20,6 +20,7 @@ package lookup
import (
"context"
"strings"
microstore "go-micro.dev/v4/store"
@@ -46,12 +47,53 @@ func NewStoreIDCache(o *options.Options) *StoreIDCache {
}
}
// Delete removes an entry from the cache
func (c *StoreIDCache) Delete(_ context.Context, spaceID, nodeID string) error {
v, err := c.cache.Read(cacheKey(spaceID, nodeID))
if err == nil {
err := c.cache.Delete(reverseCacheKey(string(v[0].Value)))
if err != nil {
return err
}
}
return c.cache.Delete(cacheKey(spaceID, nodeID))
}
// DeleteByPath removes an entry from the cache
func (c *StoreIDCache) DeleteByPath(ctx context.Context, path string) error {
spaceID, nodeID, ok := c.GetByPath(ctx, path)
if !ok {
return nil
}
err := c.cache.Delete(reverseCacheKey(path))
if err != nil {
return err
}
return c.cache.Delete(cacheKey(spaceID, nodeID))
}
// DeletePath removes only the path entry from the cache
func (c *StoreIDCache) DeletePath(ctx context.Context, path string) error {
return c.cache.Delete(reverseCacheKey(path))
}
// Add adds a new entry to the cache
func (c *StoreIDCache) Set(_ context.Context, spaceID, nodeID, val string) error {
return c.cache.Write(&microstore.Record{
err := c.cache.Write(&microstore.Record{
Key: cacheKey(spaceID, nodeID),
Value: []byte(val),
})
if err != nil {
return err
}
return c.cache.Write(&microstore.Record{
Key: reverseCacheKey(val),
Value: []byte(cacheKey(spaceID, nodeID)),
})
}
// Get returns the value for a given key
@@ -63,6 +105,23 @@ func (c *StoreIDCache) Get(_ context.Context, spaceID, nodeID string) (string, b
return string(records[0].Value), true
}
// GetByPath returns the key for a given value
func (c *StoreIDCache) GetByPath(_ context.Context, val string) (string, string, bool) {
records, err := c.cache.Read(reverseCacheKey(val))
if err != nil || len(records) == 0 {
return "", "", false
}
parts := strings.SplitN(string(records[0].Value), "!", 2)
if len(parts) != 2 {
return "", "", false
}
return parts[0], parts[1], true
}
func cacheKey(spaceid, nodeID string) string {
return spaceid + "!" + nodeID
}
func reverseCacheKey(val string) string {
return val
}
@@ -29,6 +29,7 @@ type Options struct {
UseSpaceGroups bool `mapstructure:"use_space_groups"`
WatchFS bool `mapstructure:"watch_fs"`
WatchType string `mapstructure:"watch_type"`
WatchPath string `mapstructure:"watch_path"`
WatchFolderKafkaBrokers string `mapstructure:"watch_folder_kafka_brokers"`
+2 -2
View File
@@ -78,14 +78,14 @@ func New(m map[string]interface{}, stream events.Stream) (storage.FS, error) {
var lu *lookup.Lookup
switch o.MetadataBackend {
case "xattrs":
lu = lookup.New(metadata.XattrsBackend{}, um, o)
lu = lookup.New(metadata.NewXattrsBackend(o.Root, o.FileMetadataCache), um, o)
case "messagepack":
lu = lookup.New(metadata.NewMessagePackBackend(o.Root, o.FileMetadataCache), um, o)
default:
return nil, fmt.Errorf("unknown metadata backend %s, only 'messagepack' or 'xattrs' (default) supported", o.MetadataBackend)
}
tp, err := tree.New(lu, bs, um, o, store.Create(
tp, err := tree.New(lu, bs, um, o, stream, store.Create(
store.Store(o.IDCache.Store),
store.TTL(o.IDCache.TTL),
store.Size(o.IDCache.Size),
+168 -9
View File
@@ -29,14 +29,18 @@ import (
"syscall"
"time"
"github.com/google/uuid"
"github.com/pkg/errors"
"github.com/rs/zerolog/log"
userv1beta1 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
"github.com/cs3org/reva/v2/pkg/events"
"github.com/cs3org/reva/v2/pkg/storage/fs/posix/lookup"
"github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/metadata"
"github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/metadata/prefixes"
"github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/node"
"github.com/google/uuid"
"github.com/pkg/errors"
"github.com/rs/zerolog/log"
"github.com/cs3org/reva/v2/pkg/utils"
)
type ScanDebouncer struct {
@@ -113,14 +117,82 @@ func (t *Tree) Scan(path string, forceRescan bool) error {
return nil
}
func (t *Tree) HandleFileDelete(path string) error {
// purge metadata
_ = t.lookup.(*lookup.Lookup).IDCache.DeleteByPath(context.Background(), path)
_ = t.lookup.MetadataBackend().Purge(path)
// send event
owner, spaceID, nodeID, parentID, err := t.getOwnerAndIDs(filepath.Dir(path))
if err != nil {
return err
}
t.PublishEvent(events.ItemTrashed{
Owner: owner,
Executant: owner,
Ref: &provider.Reference{
ResourceId: &provider.ResourceId{
StorageId: t.options.MountID,
SpaceId: spaceID,
OpaqueId: parentID,
},
Path: filepath.Base(path),
},
ID: &provider.ResourceId{
StorageId: t.options.MountID,
SpaceId: spaceID,
OpaqueId: nodeID,
},
Timestamp: utils.TSNow(),
})
return nil
}
func (t *Tree) getOwnerAndIDs(path string) (*userv1beta1.UserId, string, string, string, error) {
lu := t.lookup.(*lookup.Lookup)
spaceID, nodeID, err := lu.IDsForPath(context.Background(), path)
if err != nil {
return nil, "", "", "", err
}
attrs, err := t.lookup.MetadataBackend().All(context.Background(), path)
if err != nil {
return nil, "", "", "", err
}
parentID := string(attrs[prefixes.ParentidAttr])
spacePath, ok := lu.GetCachedID(context.Background(), spaceID, spaceID)
if !ok {
return nil, "", "", "", fmt.Errorf("could not find space root for path %s", path)
}
spaceAttrs, err := t.lookup.MetadataBackend().All(context.Background(), spacePath)
if err != nil {
return nil, "", "", "", err
}
owner := &userv1beta1.UserId{
Idp: string(spaceAttrs[prefixes.OwnerIDPAttr]),
OpaqueId: string(spaceAttrs[prefixes.OwnerIDAttr]),
}
return owner, nodeID, spaceID, parentID, nil
}
func (t *Tree) assimilate(item scanItem) error {
var err error
// find the space id, scope by the according user
spaceID := []byte("")
spaceCandidate := item.Path
spaceAttrs := node.Attributes{}
for strings.HasPrefix(spaceCandidate, t.options.Root) {
spaceID, err = t.lookup.MetadataBackend().Get(context.Background(), spaceCandidate, prefixes.SpaceIDAttr)
if err == nil {
spaceAttrs, err = t.lookup.MetadataBackend().All(context.Background(), spaceCandidate)
if err == nil && len(spaceAttrs[prefixes.SpaceIDAttr]) > 0 {
spaceID = spaceAttrs[prefixes.SpaceIDAttr]
if t.options.UseSpaceGroups {
// set the uid and gid for the space
fi, err := os.Stat(spaceCandidate)
@@ -147,8 +219,7 @@ func (t *Tree) assimilate(item scanItem) error {
// already assimilated?
id, err := t.lookup.MetadataBackend().Get(context.Background(), item.Path, prefixes.IDAttr)
if err == nil {
_ = t.lookup.(*lookup.Lookup).CacheID(context.Background(), string(spaceID), string(id), item.Path)
return nil
return t.lookup.(*lookup.Lookup).CacheID(context.Background(), string(spaceID), string(id), item.Path)
}
}
@@ -161,23 +232,107 @@ func (t *Tree) assimilate(item scanItem) error {
_ = unlock()
}()
user := &userv1beta1.UserId{
Idp: string(spaceAttrs[prefixes.OwnerIDPAttr]),
OpaqueId: string(spaceAttrs[prefixes.OwnerIDAttr]),
}
// check for the id attribute again after grabbing the lock, maybe the file was assimilated/created by us in the meantime
id, err = t.lookup.MetadataBackend().Get(context.Background(), item.Path, prefixes.IDAttr)
if err == nil {
previousPath, ok := t.lookup.(*lookup.Lookup).GetCachedID(context.Background(), string(spaceID), string(id))
_ = t.lookup.(*lookup.Lookup).CacheID(context.Background(), string(spaceID), string(id), item.Path)
if item.ForceRescan {
_, err = t.updateFile(item.Path, string(id), string(spaceID))
previousParentID, err := t.lookup.MetadataBackend().Get(context.Background(), item.Path, prefixes.ParentidAttr)
if err != nil {
return err
}
fi, err := t.updateFile(item.Path, string(id), string(spaceID))
if err != nil {
return err
}
// was it moved?
if ok && previousPath != item.Path {
// purge original metadata. Only delete the path entry using DeletePath(reverse lookup), not the whole entry pair.
_ = t.lookup.(*lookup.Lookup).IDCache.DeletePath(context.Background(), previousPath)
_ = t.lookup.MetadataBackend().Purge(previousPath)
if fi.IsDir() {
// if it was moved and it is a directory we need to propagate the move
go func() { _ = t.WarmupIDCache(item.Path, false) }()
}
parentID, err := t.lookup.MetadataBackend().Get(context.Background(), item.Path, prefixes.ParentidAttr)
if err == nil && len(parentID) > 0 {
ref := &provider.Reference{
ResourceId: &provider.ResourceId{
StorageId: t.options.MountID,
SpaceId: string(spaceID),
OpaqueId: string(parentID),
},
Path: filepath.Base(item.Path),
}
oldRef := &provider.Reference{
ResourceId: &provider.ResourceId{
StorageId: t.options.MountID,
SpaceId: string(spaceID),
OpaqueId: string(previousParentID),
},
Path: filepath.Base(previousPath),
}
t.PublishEvent(events.ItemMoved{
SpaceOwner: user,
Executant: user,
Owner: user,
Ref: ref,
OldReference: oldRef,
Timestamp: utils.TSNow(),
})
}
}
}
} else {
// assimilate new file
newId := uuid.New().String()
_, err = t.updateFile(item.Path, newId, string(spaceID))
fi, err := t.updateFile(item.Path, newId, string(spaceID))
if err != nil {
return err
}
ref := &provider.Reference{
ResourceId: &provider.ResourceId{
StorageId: t.options.MountID,
SpaceId: string(spaceID),
OpaqueId: newId,
},
}
if fi.IsDir() {
t.PublishEvent(events.ContainerCreated{
SpaceOwner: user,
Executant: user,
Owner: user,
Ref: ref,
Timestamp: utils.TSNow(),
})
} else {
if fi.Size() == 0 {
t.PublishEvent(events.FileTouched{
SpaceOwner: user,
Executant: user,
Ref: ref,
Timestamp: utils.TSNow(),
})
} else {
t.PublishEvent(events.UploadReady{
SpaceOwner: user,
FileRef: ref,
Timestamp: utils.TSNow(),
})
}
}
}
return nil
}
@@ -305,6 +460,10 @@ func (t *Tree) WarmupIDCache(root string, assimilate bool) error {
return err
}
if strings.HasSuffix(path, ".flock") || strings.HasSuffix(path, ".mlock") {
return nil
}
attribs, err := t.lookup.MetadataBackend().All(context.Background(), path)
if err == nil {
nodeSpaceID := attribs[prefixes.SpaceIDAttr]
@@ -32,6 +32,7 @@ func (iw *InotifyWatcher) Watch(path string) {
inotifywaitgo.CREATE,
inotifywaitgo.MOVED_TO,
inotifywaitgo.CLOSE_WRITE,
inotifywaitgo.DELETE,
},
Monitor: true,
},
@@ -46,12 +47,13 @@ func (iw *InotifyWatcher) Watch(path string) {
continue
}
switch e {
case inotifywaitgo.DELETE:
go func() { _ = iw.tree.HandleFileDelete(event.Filename) }()
case inotifywaitgo.CREATE:
go func() { _ = iw.tree.Scan(event.Filename, false) }()
case inotifywaitgo.MOVED_TO:
go func() {
_ = iw.tree.Scan(event.Filename, true)
_ = iw.tree.WarmupIDCache(event.Filename, false)
}()
case inotifywaitgo.CLOSE_WRITE:
go func() { _ = iw.tree.Scan(event.Filename, true) }()
+34 -22
View File
@@ -30,7 +30,6 @@ import (
"strings"
"time"
"github.com/gofrs/flock"
"github.com/google/uuid"
"github.com/pkg/errors"
"github.com/rs/zerolog"
@@ -43,6 +42,7 @@ import (
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
"github.com/cs3org/reva/v2/pkg/appctx"
"github.com/cs3org/reva/v2/pkg/errtypes"
"github.com/cs3org/reva/v2/pkg/events"
"github.com/cs3org/reva/v2/pkg/logger"
"github.com/cs3org/reva/v2/pkg/storage/fs/posix/lookup"
"github.com/cs3org/reva/v2/pkg/storage/fs/posix/options"
@@ -91,6 +91,7 @@ type Tree struct {
scanQueue chan scanItem
scanDebouncer *ScanDebouncer
es events.Stream
log *zerolog.Logger
}
@@ -98,7 +99,7 @@ type Tree struct {
type PermissionCheckFunc func(rp *provider.ResourcePermissions) bool
// New returns a new instance of Tree
func New(lu node.PathLookup, bs Blobstore, um usermapper.Mapper, o *options.Options, cache store.Store) (*Tree, error) {
func New(lu node.PathLookup, bs Blobstore, um usermapper.Mapper, o *options.Options, es events.Stream, cache store.Store) (*Tree, error) {
log := logger.New()
scanQueue := make(chan scanItem)
t := &Tree{
@@ -112,6 +113,7 @@ func New(lu node.PathLookup, bs Blobstore, um usermapper.Mapper, o *options.Opti
scanDebouncer: NewScanDebouncer(500*time.Millisecond, func(item scanItem) {
scanQueue <- item
}),
es: es,
log: log,
}
@@ -134,29 +136,27 @@ func New(lu node.PathLookup, bs Blobstore, um usermapper.Mapper, o *options.Opti
}
// Start watching for fs events and put them into the queue
go func() {
fileLock := flock.New(filepath.Join(o.Root, ".primary.lock"))
locked, err := fileLock.TryLock()
if err != nil {
log.Err(err).Msg("could not acquire primary lock")
return
}
if !locked {
log.Err(err).Msg("watcher is already locked")
return
}
log.Debug().Msg("acquired primary lock")
if o.WatchFS {
go t.watcher.Watch(watchPath)
go t.workScanQueue()
go func() {
_ = t.WarmupIDCache(o.Root, true)
}()
}()
}
return t, nil
}
func (t *Tree) PublishEvent(ev interface{}) {
if t.es == nil {
return
}
if err := events.Publish(context.Background(), t.es, ev); err != nil {
t.log.Error().Err(err).Interface("event", ev).Msg("failed to publish event")
}
}
// Setup prepares the tree structure
func (t *Tree) Setup() error {
err := os.MkdirAll(t.options.Root, 0700)
@@ -484,13 +484,25 @@ func (t *Tree) Delete(ctx context.Context, n *node.Node) (err error) {
// Remove lock file if it exists
_ = os.Remove(n.LockFilePath())
// finally remove the entry from the parent dir
// purge metadata
err = filepath.WalkDir(path, func(path string, _ fs.DirEntry, err error) error {
if err != nil {
return err
}
if err = t.lookup.(*lookup.Lookup).IDCache.DeleteByPath(ctx, path); err != nil {
return err
}
if err = t.lookup.MetadataBackend().Purge(path); err != nil {
return err
}
return nil
})
if err != nil {
return err
}
if err = os.RemoveAll(path); err != nil {
// To roll back changes
// TODO revert the rename
// TODO remove symlink
// Roll back changes
_ = n.RemoveXattr(ctx, prefixes.TrashOriginAttr, true)
return
}
@@ -133,7 +133,7 @@ func NewDefault(m map[string]interface{}, bs tree.Blobstore, es events.Stream) (
var lu *lookup.Lookup
switch o.MetadataBackend {
case "xattrs":
lu = lookup.New(metadata.XattrsBackend{}, o)
lu = lookup.New(metadata.NewXattrsBackend(o.Root, o.FileMetadataCache), o)
case "messagepack":
lu = lookup.New(metadata.NewMessagePackBackend(o.Root, o.FileMetadataCache), o)
default:
@@ -26,6 +26,7 @@ import (
"strconv"
"strings"
"github.com/cs3org/reva/v2/pkg/storage/cache"
"github.com/cs3org/reva/v2/pkg/storage/utils/filelocks"
"github.com/pkg/errors"
"github.com/pkg/xattr"
@@ -33,7 +34,17 @@ import (
)
// XattrsBackend stores the file attributes in extended attributes
type XattrsBackend struct{}
type XattrsBackend struct {
rootPath string
metaCache cache.FileMetadataCache
}
// NewMessageBackend returns a new XattrsBackend instance
func NewXattrsBackend(rootPath string, o cache.Config) XattrsBackend {
return XattrsBackend{
metaCache: cache.GetFileMetadataCache(o),
}
}
// Name returns the name of the backend
func (XattrsBackend) Name() string { return "xattrs" }
@@ -41,8 +52,14 @@ func (XattrsBackend) Name() string { return "xattrs" }
// Get an extended attribute value for the given key
// No file locking is involved here as reading a single xattr is
// considered to be atomic.
func (b XattrsBackend) Get(ctx context.Context, filePath, key string) ([]byte, error) {
return xattr.Get(filePath, key)
func (b XattrsBackend) Get(ctx context.Context, path, key string) ([]byte, error) {
attribs := map[string][]byte{}
err := b.metaCache.PullFromCache(b.cacheKey(path), &attribs)
if err == nil && len(attribs[key]) > 0 {
return attribs[key], err
}
return xattr.Get(path, key)
}
// GetInt64 reads a string as int64 from the xattrs
@@ -77,13 +94,29 @@ func (XattrsBackend) List(ctx context.Context, filePath string) (attribs []strin
// All reads all extended attributes for a node, protected by a
// shared file lock
func (b XattrsBackend) All(ctx context.Context, filePath string) (attribs map[string][]byte, err error) {
attrNames, err := b.List(ctx, filePath)
func (b XattrsBackend) All(ctx context.Context, path string) (map[string][]byte, error) {
return b.getAll(ctx, path, false)
}
func (b XattrsBackend) getAll(ctx context.Context, path string, skipCache bool) (map[string][]byte, error) {
attribs := map[string][]byte{}
if !skipCache {
err := b.metaCache.PullFromCache(b.cacheKey(path), &attribs)
if err == nil {
return attribs, err
}
}
attrNames, err := b.List(ctx, path)
if err != nil {
return nil, err
}
if len(attrNames) == 0 {
return attribs, nil
}
var (
xerrs = 0
xerr error
@@ -93,7 +126,7 @@ func (b XattrsBackend) All(ctx context.Context, filePath string) (attribs map[st
attribs = make(map[string][]byte, len(attrNames))
for _, name := range attrNames {
var val []byte
if val, xerr = xattr.Get(filePath, name); xerr != nil {
if val, xerr = xattr.Get(path, name); xerr != nil && !IsAttrUnset(xerr) {
xerrs++
} else {
attribs[name] = val
@@ -101,10 +134,15 @@ func (b XattrsBackend) All(ctx context.Context, filePath string) (attribs map[st
}
if xerrs > 0 {
err = errors.Wrap(xerr, "Failed to read all xattrs")
return nil, errors.Wrap(xerr, "Failed to read all xattrs")
}
return attribs, err
err = b.metaCache.PushToCache(b.cacheKey(path), attribs)
if err != nil {
return nil, err
}
return attribs, nil
}
// Set sets one attribute for the given path
@@ -142,30 +180,55 @@ func (b XattrsBackend) SetMultiple(ctx context.Context, path string, attribs map
return errors.Wrap(xerr, "Failed to set all xattrs")
}
return nil
attribs, err = b.getAll(ctx, path, true)
if err != nil {
return err
}
return b.metaCache.PushToCache(b.cacheKey(path), attribs)
}
// Remove an extended attribute key
func (XattrsBackend) Remove(ctx context.Context, filePath string, key string, acquireLock bool) (err error) {
func (b XattrsBackend) Remove(ctx context.Context, path string, key string, acquireLock bool) error {
if acquireLock {
lockedFile, err := lockedfile.OpenFile(filePath+filelocks.LockFileSuffix, os.O_CREATE|os.O_WRONLY, 0600)
lockedFile, err := lockedfile.OpenFile(path+filelocks.LockFileSuffix, os.O_CREATE|os.O_WRONLY, 0600)
if err != nil {
return err
}
defer cleanupLockfile(lockedFile)
}
return xattr.Remove(filePath, key)
err := xattr.Remove(path, key)
if err != nil {
return err
}
attribs, err := b.getAll(ctx, path, true)
if err != nil {
return err
}
return b.metaCache.PushToCache(b.cacheKey(path), attribs)
}
// IsMetaFile returns whether the given path represents a meta file
func (XattrsBackend) IsMetaFile(path string) bool { return strings.HasSuffix(path, ".meta.lock") }
// Purge purges the data of a given path
func (XattrsBackend) Purge(path string) error { return nil }
func (b XattrsBackend) Purge(path string) error {
return b.metaCache.RemoveMetadata(b.cacheKey(path))
}
// Rename moves the data for a given path to a new path
func (XattrsBackend) Rename(oldPath, newPath string) error { return nil }
func (b XattrsBackend) Rename(oldPath, newPath string) error {
data := map[string][]byte{}
err := b.metaCache.PullFromCache(b.cacheKey(oldPath), &data)
if err == nil {
err = b.metaCache.PushToCache(b.cacheKey(newPath), data)
if err != nil {
return err
}
}
return b.metaCache.RemoveMetadata(b.cacheKey(oldPath))
}
// MetadataPath returns the path of the file holding the metadata for the given path
func (XattrsBackend) MetadataPath(path string) string { return path }
@@ -199,3 +262,10 @@ func cleanupLockfile(f *lockedfile.File) {
func (b XattrsBackend) AllWithLockedSource(ctx context.Context, path string, _ io.Reader) (map[string][]byte, error) {
return b.All(ctx, path)
}
func (b XattrsBackend) cacheKey(path string) string {
// rootPath is guaranteed to have no trailing slash
// the cache key shouldn't begin with a slash as some stores drop it which can cause
// confusion
return strings.TrimPrefix(path, b.rootPath+"/")
}
@@ -50,7 +50,7 @@ func (m Migration0003) Migrate(migrator *Migrator) (Result, error) {
}
migrator.log.Info().Str("root", migrator.lu.InternalRoot()).Msg("Migrating to messagepack metadata backend...")
xattrs := metadata.XattrsBackend{}
xattrs := metadata.NewXattrsBackend(migrator.lu.InternalRoot(), cache.Config{})
mpk := metadata.NewMessagePackBackend(migrator.lu.InternalRoot(), cache.Config{})
spaces, _ := filepath.Glob(filepath.Join(migrator.lu.InternalRoot(), "spaces", "*", "*"))
@@ -92,6 +92,8 @@ type Options struct {
MaxQuota uint64 `mapstructure:"max_quota"`
DisableVersioning bool `mapstructure:"disable_versioning"`
MountID string `mapstructure:"mount_id"`
}
// AsyncPropagatorOptions holds the configuration for the async propagator
+1 -1
View File
@@ -366,7 +366,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.20.1-0.20240705133657-2b682c603c75
# github.com/cs3org/reva/v2 v2.21.0
## explicit; go 1.21
github.com/cs3org/reva/v2/cmd/revad/internal/grace
github.com/cs3org/reva/v2/cmd/revad/runtime