s3: fix --s3-versions on individual objects

Before this fix attempting to access an s3 versioned object by name in
a subdirectory of root would not find the object.

This fixes the problem and introduced an integraton test.

See: https://forum.rclone.org/t/s3-versions-cant-retrieve-old-version/36900
This commit is contained in:
Nick Craig-Wood 2023-03-21 12:44:45 +00:00
parent d481aa8613
commit 542677d807
2 changed files with 23 additions and 5 deletions

View file

@ -3119,6 +3119,7 @@ func (f *Fs) getMetaDataListing(ctx context.Context, wantRemote string) (info *s
err = f.list(ctx, listOpt{ err = f.list(ctx, listOpt{
bucket: bucket, bucket: bucket,
directory: bucketPath, directory: bucketPath,
prefix: f.rootDirectory,
recurse: true, recurse: true,
withVersions: f.opt.Versions, withVersions: f.opt.Versions,
findFile: true, findFile: true,
@ -3524,10 +3525,10 @@ type listOpt struct {
// list lists the objects into the function supplied with the opt // list lists the objects into the function supplied with the opt
// supplied. // supplied.
func (f *Fs) list(ctx context.Context, opt listOpt, fn listFn) error { func (f *Fs) list(ctx context.Context, opt listOpt, fn listFn) error {
if opt.prefix != "" {
opt.prefix += "/"
}
if !opt.findFile { if !opt.findFile {
if opt.prefix != "" {
opt.prefix += "/"
}
if opt.directory != "" { if opt.directory != "" {
opt.directory += "/" opt.directory += "/"
} }

View file

@ -6,12 +6,15 @@ import (
"context" "context"
"crypto/md5" "crypto/md5"
"fmt" "fmt"
"path"
"strings"
"testing" "testing"
"time" "time"
"github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/s3" "github.com/aws/aws-sdk-go/service/s3"
"github.com/rclone/rclone/fs" "github.com/rclone/rclone/fs"
"github.com/rclone/rclone/fs/cache"
"github.com/rclone/rclone/fs/hash" "github.com/rclone/rclone/fs/hash"
"github.com/rclone/rclone/fstest" "github.com/rclone/rclone/fstest"
"github.com/rclone/rclone/fstest/fstests" "github.com/rclone/rclone/fstest/fstests"
@ -250,7 +253,8 @@ func (f *Fs) InternalTestVersions(t *testing.T) {
time.Sleep(2 * time.Second) time.Sleep(2 * time.Second)
// Create an object // Create an object
const fileName = "test-versions.txt" const dirName = "versions"
const fileName = dirName + "/" + "test-versions.txt"
contents := random.String(100) contents := random.String(100)
item := fstest.NewItem(fileName, contents, fstest.Time("2001-05-06T04:05:06.499999999Z")) item := fstest.NewItem(fileName, contents, fstest.Time("2001-05-06T04:05:06.499999999Z"))
obj := fstests.PutTestContents(ctx, t, f, &item, contents, true) obj := fstests.PutTestContents(ctx, t, f, &item, contents, true)
@ -280,11 +284,12 @@ func (f *Fs) InternalTestVersions(t *testing.T) {
}() }()
// Read the contents // Read the contents
entries, err := f.List(ctx, "") entries, err := f.List(ctx, dirName)
require.NoError(t, err) require.NoError(t, err)
tests := 0 tests := 0
var fileNameVersion string var fileNameVersion string
for _, entry := range entries { for _, entry := range entries {
t.Log(entry)
remote := entry.Remote() remote := entry.Remote()
if remote == fileName { if remote == fileName {
t.Run("ReadCurrent", func(t *testing.T) { t.Run("ReadCurrent", func(t *testing.T) {
@ -309,6 +314,18 @@ func (f *Fs) InternalTestVersions(t *testing.T) {
require.NotNil(t, o) require.NotNil(t, o)
assert.Equal(t, int64(100), o.Size(), o.Remote()) assert.Equal(t, int64(100), o.Size(), o.Remote())
}) })
// Check we can make a NewFs from that object with a version suffix
t.Run("NewFs", func(t *testing.T) {
newPath := path.Join(fs.ConfigString(f), fileNameVersion)
// Make sure --s3-versions is set in the config of the new remote
confPath := strings.Replace(newPath, ":", ",versions:", 1)
fNew, err := cache.Get(ctx, confPath)
// This should return pointing to a file
assert.Equal(t, fs.ErrorIsFile, err)
// With the directory the directory above
assert.Equal(t, dirName, path.Base(fs.ConfigString(fNew)))
})
}) })
t.Run("VersionAt", func(t *testing.T) { t.Run("VersionAt", func(t *testing.T) {