mirror of
https://github.com/versity/versitygw.git
synced 2026-07-02 16:54:25 +00:00
8ae566d44e
Add a new non-AWS error ErrNoSpaceLeftOnDevice (HTTP 507 Insufficient Storage) to s3err. Update all call sites in the posix backend that could return ENOSPC and return the new error when the underlying filesystem has no space remaining. Fixes #2093
135 lines
3.9 KiB
Go
135 lines
3.9 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"
|
|
"github.com/versity/versitygw/s3err"
|
|
)
|
|
|
|
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 {
|
|
err := xattr.FSet(f, xattrPrefix+attribute, value)
|
|
if errors.Is(err, syscall.EROFS) {
|
|
return s3err.GetAPIError(s3err.ErrMethodNotAllowed)
|
|
}
|
|
if errors.Is(err, syscall.ENOSPC) {
|
|
return s3err.GetAPIError(s3err.ErrNoSpaceLeftOnDevice)
|
|
}
|
|
return err
|
|
}
|
|
|
|
err := xattr.Set(filepath.Join(bucket, object), xattrPrefix+attribute, value)
|
|
if errors.Is(err, syscall.EROFS) {
|
|
return s3err.GetAPIError(s3err.ErrMethodNotAllowed)
|
|
}
|
|
if errors.Is(err, syscall.ENOSPC) {
|
|
return s3err.GetAPIError(s3err.ErrNoSpaceLeftOnDevice)
|
|
}
|
|
return err
|
|
}
|
|
|
|
// 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
|
|
}
|
|
if errors.Is(err, syscall.EROFS) {
|
|
return s3err.GetAPIError(s3err.ErrMethodNotAllowed)
|
|
}
|
|
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
|
|
}
|
|
|
|
// RenameObject is a no-op for xattr because extended attributes are stored
|
|
// on the inodes and follow the file/directory when it is renamed.
|
|
func (x XattrMeta) RenameObject(_, _, _ 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
|
|
}
|