Files
versitygw/backend/posix/posix_io_helpers.go
T
niksis02 ba02c766ab fix: stop posix rewriting the current version on a copy to itself
`CopyObject` treated a destination path equal to the source path as an in-place metadata rewrite, regardless of bucket versioning. On a versioned bucket a self copy therefore edited the current version and returned its existing version id instead of creating a new one. This also defeated object lock: `CheckObjectAccess` skips the retention and legal hold checks for overwrites on version-enabled buckets because an overwrite is expected to create a new version, so a `COMPLIANCE` retained or legal held version had its metadata replaced underneath it. A self copy is now rewritten in place only when the bucket is unversioned, and otherwise goes through the regular copy path, which creates a new version and leaves the one it replaces untouched.

The rejection of a self copy that replaces nothing moved out of the in-place branch and is now applied only when the copy source carries no version id. Naming a version explicitly makes the request a regular copy, which AWS accepts even with the `COPY` metadata directive, while versitygw answered `InvalidRequest`.

Source tagging for a `COPY` tagging directive is now read before `PutObject` writes the destination rather than after. A self copy replaces the source object's attributes, so the later read returned nothing and the tags were dropped from the new version.
2026-09-20 17:40:19 +04:00

75 lines
1.8 KiB
Go

// Copyright 2026 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 posix
import (
"bufio"
"errors"
"io"
"log"
"sync"
)
func withReadBufferSize(r io.ReadCloser, size int) io.ReadCloser {
if size <= 0 {
return r
}
return &bufferedReadCloser{
r: bufio.NewReaderSize(r, size),
c: r,
}
}
type bufferedReadCloser struct {
r *bufio.Reader
c io.Closer
}
func (b *bufferedReadCloser) Read(p []byte) (int, error) {
return b.r.Read(p)
}
func (b *bufferedReadCloser) Close() error {
return b.c.Close()
}
// closeOnEOFReader closes c once r is drained, for readers whose source has
// to be released before the caller is done with the reader.
type closeOnEOFReader struct {
r io.Reader
c io.Closer
closed bool
}
func (e *closeOnEOFReader) Read(p []byte) (int, error) {
n, err := e.r.Read(p)
if errors.Is(err, io.EOF) && !e.closed {
e.closed = true
e.c.Close()
}
return n, err
}
var odirectUnsupportedWarnByOp sync.Map
func warnODirectUnsupportedOnce(op string, err error) {
v, _ := odirectUnsupportedWarnByOp.LoadOrStore(op, &sync.Once{})
v.(*sync.Once).Do(func() {
log.Printf("WARNING: O_DIRECT is enabled but unsupported (%s: %v); falling back to buffered I/O. This warning is shown once per operation.", op, err)
})
}