mirror of
https://github.com/versity/versitygw.git
synced 2026-01-07 12:15:18 +00:00
This fixes the cases for racing uploads with the same object names. Before we were making some bad assumptions about what would cause an error when trying to link/rename the final object name into the namespace, but missed the case that another upload for the same name could be racing with this upload and causing an incorrect error. This also changes the order of setting metadata to prevent accidental setting of metadata for the current upload to another racing upload. This also fix auth.CheckObjectAccess() when objects are removed while this runs. Fixes #854
115 lines
3.2 KiB
Go
115 lines
3.2 KiB
Go
// Copyright 2024 Versity Software
|
|
// This file is 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.
|
|
|
|
package meta
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"syscall"
|
|
|
|
"github.com/pkg/xattr"
|
|
)
|
|
|
|
const (
|
|
xattrPrefix = "user."
|
|
)
|
|
|
|
var (
|
|
// ErrNoSuchKey is returned when the key does not exist.
|
|
ErrNoSuchKey = errors.New("no such key")
|
|
)
|
|
|
|
type XattrMeta struct{}
|
|
|
|
// RetrieveAttribute retrieves the value of a specific attribute for an object in a bucket.
|
|
func (x XattrMeta) RetrieveAttribute(f *os.File, bucket, object, attribute string) ([]byte, error) {
|
|
if f != nil {
|
|
b, err := xattr.FGet(f, xattrPrefix+attribute)
|
|
if errors.Is(err, xattr.ENOATTR) {
|
|
return nil, ErrNoSuchKey
|
|
}
|
|
return b, err
|
|
}
|
|
|
|
b, err := xattr.Get(filepath.Join(bucket, object), xattrPrefix+attribute)
|
|
if errors.Is(err, xattr.ENOATTR) {
|
|
return nil, ErrNoSuchKey
|
|
}
|
|
return b, err
|
|
}
|
|
|
|
// StoreAttribute stores the value of a specific attribute for an object in a bucket.
|
|
func (x XattrMeta) StoreAttribute(f *os.File, bucket, object, attribute string, value []byte) error {
|
|
if f != nil {
|
|
return xattr.FSet(f, xattrPrefix+attribute, value)
|
|
}
|
|
|
|
return xattr.Set(filepath.Join(bucket, object), xattrPrefix+attribute, value)
|
|
}
|
|
|
|
// DeleteAttribute removes the value of a specific attribute for an object in a bucket.
|
|
func (x XattrMeta) DeleteAttribute(bucket, object, attribute string) error {
|
|
err := xattr.Remove(filepath.Join(bucket, object), xattrPrefix+attribute)
|
|
if errors.Is(err, xattr.ENOATTR) {
|
|
return ErrNoSuchKey
|
|
}
|
|
return err
|
|
}
|
|
|
|
// DeleteAttributes is not implemented for xattr since xattrs
|
|
// are automatically removed when the file is deleted.
|
|
func (x XattrMeta) DeleteAttributes(bucket, object string) error {
|
|
return nil
|
|
}
|
|
|
|
// ListAttributes lists all attributes for an object in a bucket.
|
|
func (x XattrMeta) ListAttributes(bucket, object string) ([]string, error) {
|
|
attrs, err := xattr.List(filepath.Join(bucket, object))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
attributes := make([]string, 0, len(attrs))
|
|
for _, attr := range attrs {
|
|
if !isUserAttr(attr) {
|
|
continue
|
|
}
|
|
attributes = append(attributes, strings.TrimPrefix(attr, xattrPrefix))
|
|
}
|
|
return attributes, nil
|
|
}
|
|
|
|
func isUserAttr(attr string) bool {
|
|
return strings.HasPrefix(attr, xattrPrefix)
|
|
}
|
|
|
|
// Test is a helper function to test if xattrs are supported.
|
|
func (x XattrMeta) Test(path string) error {
|
|
// check for platform support
|
|
if !xattr.XATTR_SUPPORTED {
|
|
return fmt.Errorf("xattrs are not supported on this platform")
|
|
}
|
|
|
|
// check if the filesystem supports xattrs
|
|
_, err := xattr.Get(path, "user.test")
|
|
if errors.Is(err, syscall.ENOTSUP) {
|
|
return fmt.Errorf("xattrs are not supported on this filesystem")
|
|
}
|
|
|
|
return nil
|
|
}
|