diff --git a/go.mod b/go.mod index 87f7aa7edc..4d7da32f80 100644 --- a/go.mod +++ b/go.mod @@ -86,7 +86,6 @@ require ( google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e google.golang.org/grpc v1.50.1 google.golang.org/protobuf v1.28.1 - gopkg.in/ini.v1 v1.67.0 gotest.tools v2.2.0+incompatible ) @@ -206,6 +205,7 @@ require ( golang.org/x/time v0.1.0 // indirect golang.org/x/tools v0.4.0 // indirect google.golang.org/appengine v1.6.7 // indirect + gopkg.in/ini.v1 v1.66.6 // indirect gopkg.in/square/go-jose.v2 v2.6.0 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect diff --git a/go.sum b/go.sum index 17a76c4773..5aa60c0b92 100644 --- a/go.sum +++ b/go.sum @@ -1555,8 +1555,8 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/h2non/gock.v1 v1.0.14/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE= gopkg.in/h2non/gock.v1 v1.1.2/go.mod h1:n7UGz/ckNChHiK05rDoiC4MYSunEC/lyaUm2WWaDva0= -gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= -gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.66.6 h1:LATuAqN/shcYAOkv3wl2L4rkaKqkcgTBQjOyYDvcPKI= +gopkg.in/ini.v1 v1.66.6/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/telebot.v3 v3.0.0/go.mod h1:7rExV8/0mDDNu9epSrDm/8j22KLaActH1Tbee6YjzWg= diff --git a/pkg/storage/utils/decomposedfs/decomposedfs.go b/pkg/storage/utils/decomposedfs/decomposedfs.go index bdb5fd657e..54be5afe49 100644 --- a/pkg/storage/utils/decomposedfs/decomposedfs.go +++ b/pkg/storage/utils/decomposedfs/decomposedfs.go @@ -107,10 +107,12 @@ func NewDefault(m map[string]interface{}, bs tree.Blobstore, es events.Stream) ( switch o.MetadataBackend { case "xattrs": lu = lookup.New(metadata.XattrsBackend{}, o) + case "messagepack": + lu = lookup.New(metadata.NewMessagePackBackend(o.Root, o.FileMetadataCache), o) case "ini": lu = lookup.New(metadata.NewIniBackend(o.Root, o.FileMetadataCache), o) default: - return nil, fmt.Errorf("unknown metadata backend %s, only 'ini' or 'xattrs' (default) supported", o.MetadataBackend) + return nil, fmt.Errorf("unknown metadata backend %s, only 'ini', 'messagepack' or 'xattrs' (default) supported", o.MetadataBackend) } tp := tree.New(o.Root, o.TreeTimeAccounting, o.TreeSizeAccounting, lu, bs) diff --git a/pkg/storage/utils/decomposedfs/metadata/ini_backend.go b/pkg/storage/utils/decomposedfs/metadata/messagepack_backend.go similarity index 57% rename from pkg/storage/utils/decomposedfs/metadata/ini_backend.go rename to pkg/storage/utils/decomposedfs/metadata/messagepack_backend.go index 3e3dbe022d..abe108a2a0 100644 --- a/pkg/storage/utils/decomposedfs/metadata/ini_backend.go +++ b/pkg/storage/utils/decomposedfs/metadata/messagepack_backend.go @@ -19,28 +19,22 @@ package metadata import ( - "encoding/base64" "io" "os" "path/filepath" "strconv" "strings" "time" - "unicode" "github.com/cs3org/reva/v2/pkg/storage/cache" "github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/options" "github.com/pkg/xattr" "github.com/rogpeppe/go-internal/lockedfile" - "gopkg.in/ini.v1" + "github.com/shamaton/msgpack/v2" ) -func init() { - ini.PrettyFormat = false // Disable alignment of values for performance reasons -} - -// IniBackend persists the attributes in INI format inside the file -type IniBackend struct { +// MessagePackBackend persists the attributes in messagepack format inside the file +type MessagePackBackend struct { rootPath string metaCache cache.FileMetadataCache } @@ -51,48 +45,47 @@ type readWriteCloseSeekTruncater interface { Truncate(int64) error } -// NewIniBackend returns a new IniBackend instance -func NewIniBackend(rootPath string, o options.CacheOptions) IniBackend { - ini.PrettyFormat = false - return IniBackend{ +// NewMessagePackBackend returns a new MessagePackBackend instance +func NewMessagePackBackend(rootPath string, o options.CacheOptions) MessagePackBackend { + return MessagePackBackend{ rootPath: filepath.Clean(rootPath), metaCache: cache.GetFileMetadataCache(o.CacheStore, o.CacheNodes, o.CacheDatabase, "filemetadata", 24*time.Hour), } } // All reads all extended attributes for a node -func (b IniBackend) All(path string) (map[string][]byte, error) { +func (b MessagePackBackend) All(path string) (map[string][]byte, error) { path = b.MetadataPath(path) - return b.loadMeta(path) + return b.loadAttributes(path) } // Get an extended attribute value for the given key -func (b IniBackend) Get(path, key string) ([]byte, error) { +func (b MessagePackBackend) Get(path, key string) ([]byte, error) { path = b.MetadataPath(path) - attribs, err := b.loadMeta(path) + attribs, err := b.loadAttributes(path) if err != nil { return []byte{}, err } val, ok := attribs[key] if !ok { - return []byte{}, &xattr.Error{Op: "ini.get", Path: path, Name: key, Err: xattr.ENOATTR} + return []byte{}, &xattr.Error{Op: "mpk.get", Path: path, Name: key, Err: xattr.ENOATTR} } return val, nil } // GetInt64 reads a string as int64 from the xattrs -func (b IniBackend) GetInt64(path, key string) (int64, error) { +func (b MessagePackBackend) GetInt64(path, key string) (int64, error) { path = b.MetadataPath(path) - attribs, err := b.loadMeta(path) + attribs, err := b.loadAttributes(path) if err != nil { return 0, err } val, ok := attribs[key] if !ok { - return 0, &xattr.Error{Op: "ini.get", Path: path, Name: key, Err: xattr.ENOATTR} + return 0, &xattr.Error{Op: "mpk.get", Path: path, Name: key, Err: xattr.ENOATTR} } i, err := strconv.ParseInt(string(val), 10, 64) if err != nil { @@ -103,10 +96,10 @@ func (b IniBackend) GetInt64(path, key string) (int64, error) { // List retrieves a list of names of extended attributes associated with the // given path in the file system. -func (b IniBackend) List(path string) ([]string, error) { +func (b MessagePackBackend) List(path string) ([]string, error) { path = b.MetadataPath(path) - attribs, err := b.loadMeta(path) + attribs, err := b.loadAttributes(path) if err != nil { return nil, err } @@ -118,21 +111,21 @@ func (b IniBackend) List(path string) ([]string, error) { } // Set sets one attribute for the given path -func (b IniBackend) Set(path, key string, val []byte) error { +func (b MessagePackBackend) Set(path, key string, val []byte) error { return b.SetMultiple(path, map[string][]byte{key: val}, true) } // SetMultiple sets a set of attribute for the given path -func (b IniBackend) SetMultiple(path string, attribs map[string][]byte, acquireLock bool) error { - return b.saveIni(path, attribs, nil, acquireLock) +func (b MessagePackBackend) SetMultiple(path string, attribs map[string][]byte, acquireLock bool) error { + return b.saveAttributes(path, attribs, nil, acquireLock) } // Remove an extended attribute key -func (b IniBackend) Remove(path, key string) error { - return b.saveIni(path, nil, []string{key}, true) +func (b MessagePackBackend) Remove(path, key string) error { + return b.saveAttributes(path, nil, []string{key}, true) } -func (b IniBackend) saveIni(path string, setAttribs map[string][]byte, deleteAttribs []string, acquireLock bool) error { +func (b MessagePackBackend) saveAttributes(path string, setAttribs map[string][]byte, deleteAttribs []string, acquireLock bool) error { var ( f readWriteCloseSeekTruncater err error @@ -152,25 +145,24 @@ func (b IniBackend) saveIni(path string, setAttribs map[string][]byte, deleteAtt _ = b.metaCache.RemoveMetadata(path) // Read current state - iniBytes, err := io.ReadAll(f) + msgBytes, err := io.ReadAll(f) if err != nil { return err } - iniFile, err := ini.Load(iniBytes) - if err != nil { - return err + attribs := map[string][]byte{} + if len(msgBytes) > 0 { + err = msgpack.Unmarshal(msgBytes, &attribs) + if err != nil { + return err + } } - // Prepare new metadata - iniAttribs, err := decodeAttribs(iniFile) - if err != nil { - return err - } + // set new metadata for key, val := range setAttribs { - iniAttribs[key] = val + attribs[key] = val } for _, key := range deleteAttribs { - delete(iniAttribs, key) + delete(attribs, key) } // Truncate file @@ -184,23 +176,16 @@ func (b IniBackend) saveIni(path string, setAttribs map[string][]byte, deleteAtt } // Write new metadata to file - ini, err := ini.Load([]byte{}) - if err != nil { - return err - } - for key, val := range encodeAttribs(iniAttribs) { - ini.Section("").Key(key).SetValue(val) - } - _, err = ini.WriteTo(f) + msgpack.NewEncoder(f).Encode(attribs) if err != nil { return err } - return b.metaCache.PushToCache(b.cacheKey(path), iniAttribs) + return b.metaCache.PushToCache(b.cacheKey(path), attribs) } -func (b IniBackend) loadMeta(path string) (map[string][]byte, error) { - var attribs map[string][]byte +func (b MessagePackBackend) loadAttributes(path string) (map[string][]byte, error) { + attribs := map[string][]byte{} err := b.metaCache.PullFromCache(b.cacheKey(path), &attribs) if err == nil { return attribs, err @@ -214,7 +199,7 @@ func (b IniBackend) loadMeta(path string) (map[string][]byte, error) { // some of the caller rely on ENOTEXISTS to be returned when the // actual file (not the metafile) does not exist in order to // determine whether a node exists or not -> stat the actual node - _, err := os.Stat(strings.TrimSuffix(path, ".ini")) + _, err := os.Stat(strings.TrimSuffix(path, ".mpk")) if err != nil { return nil, err } @@ -223,14 +208,15 @@ func (b IniBackend) loadMeta(path string) (map[string][]byte, error) { } defer lockedFile.Close() - iniFile, err := ini.Load(lockedFile) + msgBytes, err := io.ReadAll(lockedFile) if err != nil { return nil, err } - - attribs, err = decodeAttribs(iniFile) - if err != nil { - return nil, err + if len(msgBytes) > 0 { + err = msgpack.Unmarshal(msgBytes, &attribs) + if err != nil { + return nil, err + } } err = b.metaCache.PushToCache(b.cacheKey(path), attribs) @@ -242,10 +228,10 @@ func (b IniBackend) loadMeta(path string) (map[string][]byte, error) { } // IsMetaFile returns whether the given path represents a meta file -func (IniBackend) IsMetaFile(path string) bool { return strings.HasSuffix(path, ".ini") } +func (MessagePackBackend) IsMetaFile(path string) bool { return strings.HasSuffix(path, ".mpk") } // Purge purges the data of a given path -func (b IniBackend) Purge(path string) error { +func (b MessagePackBackend) Purge(path string) error { if err := b.metaCache.RemoveMetadata(b.cacheKey(path)); err != nil { return err } @@ -253,7 +239,7 @@ func (b IniBackend) Purge(path string) error { } // Rename moves the data for a given path to a new path -func (b IniBackend) Rename(oldPath, newPath string) error { +func (b MessagePackBackend) Rename(oldPath, newPath string) error { data := map[string]string{} _ = b.metaCache.PullFromCache(b.cacheKey(oldPath), &data) err := b.metaCache.RemoveMetadata(b.cacheKey(oldPath)) @@ -269,57 +255,11 @@ func (b IniBackend) Rename(oldPath, newPath string) error { } // MetadataPath returns the path of the file holding the metadata for the given path -func (IniBackend) MetadataPath(path string) string { return path + ".ini" } +func (MessagePackBackend) MetadataPath(path string) string { return path + ".mpk" } -func (b IniBackend) cacheKey(path string) string { +func (b MessagePackBackend) 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+"/") } - -func needsEncoding(s []byte) bool { - if len(s) == 0 { - return false - } - - if s[0] == '\'' || s[0] == '"' || s[0] == '`' { - return true - } - - for i := 0; i < len(s); i++ { - if s[i] < 32 || s[i] >= unicode.MaxASCII { // ASCII 127 = Del - we don't want that - return true - } - } - return false -} - -func encodeAttribs(attribs map[string][]byte) map[string]string { - encAttribs := map[string]string{} - for key, val := range attribs { - if needsEncoding(val) { - encAttribs["base64:"+key] = base64.StdEncoding.EncodeToString(val) - } else { - encAttribs[key] = string(val) - } - } - return encAttribs -} - -func decodeAttribs(iniFile *ini.File) (map[string][]byte, error) { - decodedAttributes := map[string][]byte{} - for key, val := range iniFile.Section("").KeysHash() { - if strings.HasPrefix(key, "base64:") { - key = strings.TrimPrefix(key, "base64:") - valBytes, err := base64.StdEncoding.DecodeString(val) - if err != nil { - return nil, err - } - decodedAttributes[key] = valBytes - } else { - decodedAttributes[key] = []byte(val) - } - } - return decodedAttributes, nil -} diff --git a/pkg/storage/utils/decomposedfs/metadata/metadata_test.go b/pkg/storage/utils/decomposedfs/metadata/metadata_test.go index 34a049afcd..b889b70ea3 100644 --- a/pkg/storage/utils/decomposedfs/metadata/metadata_test.go +++ b/pkg/storage/utils/decomposedfs/metadata/metadata_test.go @@ -21,7 +21,6 @@ package metadata_test import ( "os" "path" - "strings" "github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/metadata" "github.com/cs3org/reva/v2/pkg/storage/utils/decomposedfs/options" @@ -57,62 +56,41 @@ var _ = Describe("Backend", func() { } }) - Describe("IniBackend", func() { + Describe("MessagePackBackend", func() { BeforeEach(func() { - backend = metadata.NewIniBackend(tmpdir, options.CacheOptions{}) + backend = metadata.NewMessagePackBackend(tmpdir, options.CacheOptions{}) }) Describe("Set", func() { It("sets an attribute", func() { - err := backend.Set(file, "foo", []byte("bar")) + data := []byte(`bar\`) + err := backend.Set(file, "foo", data) Expect(err).ToNot(HaveOccurred()) - content, err := os.ReadFile(metafile) + readData, err := backend.Get(file, "foo") Expect(err).ToNot(HaveOccurred()) - Expect(string(content)).To(Equal("foo = bar\n")) + Expect(readData).To(Equal(data)) }) - It("updates an attribute", func() { - err := backend.Set(file, "foo", []byte("bar")) - Expect(err).ToNot(HaveOccurred()) - err = backend.Set(file, "foo", []byte("baz")) - Expect(err).ToNot(HaveOccurred()) - - content, err := os.ReadFile(metafile) - Expect(err).ToNot(HaveOccurred()) - Expect(string(content)).To(Equal("foo = baz\n")) - }) - - It("encodes where needed", func() { - err := backend.Set(file, "user.ocis.cs.foo", []byte("bar")) - Expect(err).ToNot(HaveOccurred()) - - content, err := os.ReadFile(metafile) - Expect(err).ToNot(HaveOccurred()) - Expect(string(content)).To(Equal("user.ocis.cs.foo = bar\n")) - - err = backend.Set(file, "user.ocis.cs.foo", []byte{200, 201, 202}) + It("handles funny strings", func() { + data := []byte(`bar\`) + err := backend.Set(file, "foo", data) Expect(err).ToNot(HaveOccurred()) - content, err = os.ReadFile(metafile) + readData, err := backend.Get(file, "foo") Expect(err).ToNot(HaveOccurred()) - Expect(string(content)).To(Equal("`base64:user.ocis.cs.foo` = yMnK\n")) + Expect(readData).To(Equal(data)) }) - It("doesn't encode already encoded attributes", func() { - err := backend.Set(file, "user.ocis.cs.foo", []byte{200, 201, 202}) - Expect(err).ToNot(HaveOccurred()) - - content, err := os.ReadFile(metafile) + It("updates an attribute", func() { + err := backend.Set(file, "foo", []byte("bar")) Expect(err).ToNot(HaveOccurred()) - Expect(string(content)).To(Equal("`base64:user.ocis.cs.foo` = yMnK\n")) - - err = backend.Set(file, "user.something", []byte("doesn'tmatter")) + err = backend.Set(file, "foo", []byte("baz")) Expect(err).ToNot(HaveOccurred()) - content, err = os.ReadFile(metafile) + readData, err := backend.Get(file, "foo") Expect(err).ToNot(HaveOccurred()) - Expect(string(content)).To(ContainSubstring("`base64:user.ocis.cs.foo` = yMnK\n")) + Expect(readData).To(Equal([]byte("baz"))) }) It("sets an empty attribute", func() { @@ -124,80 +102,64 @@ var _ = Describe("Backend", func() { v, err := backend.Get(file, "foo") Expect(err).ToNot(HaveOccurred()) - Expect(v).To(Equal("")) + Expect(v).To(Equal([]byte{})) }) }) Describe("SetMultiple", func() { It("sets attributes", func() { - err := backend.SetMultiple(file, map[string][]byte{"foo": []byte("bar"), "baz": []byte("qux")}, true) + data := map[string][]byte{"foo": []byte("bar"), "baz": []byte("qux")} + err := backend.SetMultiple(file, data, true) Expect(err).ToNot(HaveOccurred()) - content, err := os.ReadFile(metafile) + readData, err := backend.All(file) Expect(err).ToNot(HaveOccurred()) - lines := strings.Split(strings.Trim(string(content), "\n"), "\n") - Expect(lines).To(ConsistOf("foo = bar", "baz = qux")) + Expect(readData).To(Equal(data)) }) It("updates an attribute", func() { - err := backend.Set(file, "foo", []byte("bar")) - Expect(err).ToNot(HaveOccurred()) - err = backend.SetMultiple(file, map[string][]byte{"foo": []byte("bar"), "baz": []byte("qux")}, true) - Expect(err).ToNot(HaveOccurred()) + err := backend.Set(file, "foo", []byte("something")) - content, err := os.ReadFile(metafile) + data := map[string][]byte{"foo": []byte("bar"), "baz": []byte("qux")} Expect(err).ToNot(HaveOccurred()) - lines := strings.Split(strings.Trim(string(content), "\n"), "\n") - Expect(lines).To(ConsistOf("foo = bar", "baz = qux")) - }) - - It("encodes where needed", func() { - err := backend.SetMultiple(file, map[string][]byte{ - "user.ocis.something.foo": []byte("bar"), - "user.ocis.cs.foo": []byte{200, 201, 202}, - "user.ocis.md.foo": []byte{200, 201, 202}, - "user.ocis.grant.foo": []byte("bar"), - }, true) + err = backend.SetMultiple(file, data, true) Expect(err).ToNot(HaveOccurred()) - content, err := os.ReadFile(metafile) + readData, err := backend.All(file) Expect(err).ToNot(HaveOccurred()) - expected := []string{ - "user.ocis.something.foo=bar", - "`base64:user.ocis.cs.foo`=yMnK", - "`base64:user.ocis.md.foo`=yMnK", - "user.ocis.grant.foo=bar"} - Expect(strings.Split(strings.ReplaceAll(strings.Trim(string(content), "\n"), " ", ""), "\n")).To(ConsistOf(expected)) + Expect(readData).To(Equal(data)) }) }) Describe("All", func() { It("returns the entries", func() { - err := os.WriteFile(metafile, []byte("foo=123\nbar=baz"), 0600) + data := map[string][]byte{"foo": []byte("123"), "bar": []byte("baz")} + err := backend.SetMultiple(file, data, true) Expect(err).ToNot(HaveOccurred()) v, err := backend.All(file) Expect(err).ToNot(HaveOccurred()) Expect(len(v)).To(Equal(2)) - Expect(v["foo"]).To(Equal("123")) + Expect(v["foo"]).To(Equal([]byte("123"))) Expect(v["bar"]).To(Equal([]byte("baz"))) }) It("returns an empty map", func() { v, err := backend.All(file) Expect(err).ToNot(HaveOccurred()) - Expect(v).To(Equal(map[string]string{})) + Expect(v).To(Equal(map[string][]byte{})) }) }) Describe("List", func() { It("returns the entries", func() { - err := os.WriteFile(metafile, []byte("foo = 123\nbar = baz"), 0600) + data := map[string][]byte{"foo": []byte("123"), "bar": []byte("baz")} + err := backend.SetMultiple(file, data, true) Expect(err).ToNot(HaveOccurred()) v, err := backend.List(file) Expect(err).ToNot(HaveOccurred()) - Expect(v).To(ConsistOf("foo", []byte("bar"))) + Expect(v).To(ConsistOf("foo", "bar")) }) It("returns an empty list", func() { @@ -209,7 +171,8 @@ var _ = Describe("Backend", func() { Describe("Get", func() { It("returns the attribute", func() { - err := os.WriteFile(metafile, []byte("foo = \"bar\"\n"), 0600) + data := map[string][]byte{"foo": []byte("bar")} + err := backend.SetMultiple(file, data, true) Expect(err).ToNot(HaveOccurred()) v, err := backend.Get(file, "foo") @@ -225,7 +188,8 @@ var _ = Describe("Backend", func() { Describe("GetInt64", func() { It("returns the attribute", func() { - err := os.WriteFile(metafile, []byte("foo=123\n"), 0600) + data := map[string][]byte{"foo": []byte("123")} + err := backend.SetMultiple(file, data, true) Expect(err).ToNot(HaveOccurred()) v, err := backend.GetInt64(file, "foo") @@ -239,9 +203,10 @@ var _ = Describe("Backend", func() { }) }) - Describe("Get", func() { + Describe("Remove", func() { It("deletes an attribute", func() { - err := os.WriteFile(metafile, []byte("foo=bar\n"), 0600) + data := map[string][]byte{"foo": []byte("bar")} + err := backend.SetMultiple(file, data, true) Expect(err).ToNot(HaveOccurred()) v, err := backend.Get(file, "foo") @@ -258,7 +223,7 @@ var _ = Describe("Backend", func() { Describe("IsMetaFile", func() { It("returns true", func() { - Expect(backend.IsMetaFile("foo.ini")).To(BeTrue()) + Expect(backend.IsMetaFile("foo.mpk")).To(BeTrue()) }) It("returns false", func() { diff --git a/pkg/storage/utils/decomposedfs/node/node.go b/pkg/storage/utils/decomposedfs/node/node.go index 9725ae2193..0fbb35b99d 100644 --- a/pkg/storage/utils/decomposedfs/node/node.go +++ b/pkg/storage/utils/decomposedfs/node/node.go @@ -312,8 +312,13 @@ func ReadNode(ctx context.Context, lu PathLookup, spaceID, nodeID string, canLis n.Name = attrs.String(prefixes.NameAttr) n.ParentID = attrs.String(prefixes.ParentidAttr) if n.ParentID == "" { - d, _ := os.ReadFile(n.InternalPath() + ".ini") - appctx.GetLogger(ctx).Error().Str("nodeid", n.ID).Str("parentid", n.ParentID).Interface("attrs", attrs).Str("ini", string(d)).Msg("missing parent id") + d, _ := os.ReadFile(lu.MetadataBackend().MetadataPath(n.InternalPath())) + switch lu.MetadataBackend().(type) { + case metadata.IniBackend: + appctx.GetLogger(ctx).Error().Str("nodeid", n.ID).Interface("attrs", attrs).Str("ini", string(d)).Msg("missing parent id") + case metadata.MessagePackBackend: + appctx.GetLogger(ctx).Error().Str("nodeid", n.ID).Interface("attrs", attrs).Bytes("messagepack", d).Msg("missing parent id") + } return nil, errtypes.InternalError("Missing parent ID on node") } // TODO why do we stat the parent? to determine if the current node is in the trash we would need to traverse all parents... diff --git a/pkg/storage/utils/decomposedfs/spaces.go b/pkg/storage/utils/decomposedfs/spaces.go index 710800b9a5..31c857c826 100644 --- a/pkg/storage/utils/decomposedfs/spaces.go +++ b/pkg/storage/utils/decomposedfs/spaces.go @@ -865,7 +865,7 @@ func (fs *Decomposedfs) storageSpaceFromNode(ctx context.Context, n *node.Node, return nil, err } - // quota + // if quota is set try parsing it as int64, otherwise don't bother if q, err := spaceAttributes.Int64(prefixes.QuotaAttr); err == nil && q >= 0 { // make sure we have a proper signed int // we use the same magic numbers to indicate: diff --git a/pkg/storage/utils/decomposedfs/tree/tree.go b/pkg/storage/utils/decomposedfs/tree/tree.go index 9ab30331f5..bc56fe65c7 100644 --- a/pkg/storage/utils/decomposedfs/tree/tree.go +++ b/pkg/storage/utils/decomposedfs/tree/tree.go @@ -781,7 +781,7 @@ func (t *Tree) Propagate(ctx context.Context, n *node.Node, sizeDiff int64) (err var f *lockedfile.File // lock node before reading treesize or tree time switch t.lookup.MetadataBackend().(type) { - case metadata.IniBackend: + case metadata.IniBackend, metadata.MessagePackBackend: f, err = lockedfile.OpenFile(t.lookup.MetadataBackend().MetadataPath(n.InternalPath()), os.O_RDWR|os.O_CREATE, 0600) case metadata.XattrsBackend: // we have to use dedicated lockfiles to lock directories diff --git a/pkg/storage/utils/decomposedfs/upload/processing.go b/pkg/storage/utils/decomposedfs/upload/processing.go index 33fe4501fb..fc4ed3689d 100644 --- a/pkg/storage/utils/decomposedfs/upload/processing.go +++ b/pkg/storage/utils/decomposedfs/upload/processing.go @@ -333,14 +333,17 @@ func initNewNode(upload *Upload, n *node.Node, fsize uint64) (*lockedfile.File, return nil, err } - if _, ok := upload.lu.MetadataBackend().(metadata.IniBackend); ok { - // for the ini backend we also need to touch the actual node file here. + switch upload.lu.MetadataBackend().(type) { + case metadata.IniBackend, metadata.MessagePackBackend: + // for the ini and metadata backend we also need to touch the actual node file here. // it stores the mtime of the resource, which must not change when we update the ini file h, err := os.OpenFile(n.InternalPath(), os.O_CREATE, 0600) if err != nil { return f, err } h.Close() + case metadata.XattrsBackend: + // nothing to do } if _, err := node.CheckQuota(n.SpaceRoot, false, 0, fsize); err != nil {