1
0
mirror of https://github.com/gilbertchen/duplicacy synced 2025-12-06 00:03:38 +00:00

Compare commits

...

3 Commits

Author SHA1 Message Date
jkl
dc273e310e Merge 915776161f into 065ae50868 2025-01-19 13:31:00 -06:00
Gilbert Chen
065ae50868 Improve parsing logic for swift storage URLs that contain multiple '@'
Parse the storage URL first, then use a regex to ensure the server name is
correctly identified starting after the final '@'.
2024-12-19 08:54:22 -05:00
John K. Luebs
915776161f Use S3 ListObjectsV2 for listing files
ListObjects has been deprecated since 2016 and ListObjectsV2 with use of
explicit pagination tokens is more performant for large listings as well.

This also mitigates an issue with iDrive E2 where the StartAfter/Marker
is included in the output, leading to duplicate entries. Right now this
causes an exhaustive prune to delete chunks erroneously flagged as
duplicate, destroying the storage.
2023-09-23 22:17:22 -05:00
2 changed files with 30 additions and 33 deletions

View File

@@ -90,48 +90,40 @@ func (storage *S3Storage) ListFiles(threadIndex int, dir string) (files []string
if dir == "snapshots/" {
dir = storage.storageDir + dir
input := s3.ListObjectsInput{
input := s3.ListObjectsV2Input{
Bucket: aws.String(storage.bucket),
Prefix: aws.String(dir),
Delimiter: aws.String("/"),
MaxKeys: aws.Int64(1000),
}
output, err := storage.client.ListObjects(&input)
err := storage.client.ListObjectsV2Pages(&input, func(page *s3.ListObjectsV2Output, lastPage bool) bool {
for _, subDir := range page.CommonPrefixes {
files = append(files, (*subDir.Prefix)[len(dir):])
}
return true
})
if err != nil {
return nil, nil, err
}
for _, subDir := range output.CommonPrefixes {
files = append(files, (*subDir.Prefix)[len(dir):])
}
return files, nil, nil
} else {
dir = storage.storageDir + dir
marker := ""
for {
input := s3.ListObjectsInput{
Bucket: aws.String(storage.bucket),
Prefix: aws.String(dir),
MaxKeys: aws.Int64(1000),
Marker: aws.String(marker),
}
input := s3.ListObjectsV2Input{
Bucket: aws.String(storage.bucket),
Prefix: aws.String(dir),
MaxKeys: aws.Int64(1000),
}
output, err := storage.client.ListObjects(&input)
if err != nil {
return nil, nil, err
}
for _, object := range output.Contents {
err := storage.client.ListObjectsV2Pages(&input, func(page *s3.ListObjectsV2Output, lastPage bool) bool {
for _, object := range page.Contents {
files = append(files, (*object.Key)[len(dir):])
sizes = append(sizes, *object.Size)
}
if !*output.IsTruncated {
break
}
marker = *output.Contents[len(output.Contents)-1].Key
return true
})
if err != nil {
return nil, nil, err
}
return files, sizes, nil
}

View File

@@ -9,6 +9,7 @@ import (
"strconv"
"strings"
"time"
"regexp"
"github.com/ncw/swift/v2"
)
@@ -42,13 +43,6 @@ func CreateSwiftStorage(storageURL string, key string, threads int) (storage *Sw
}
}
// Take out the user name if there is one
if strings.Contains(storageURL, "@") {
userAndURL := strings.Split(storageURL, "@")
arguments["user"] = userAndURL[0]
storageURL = userAndURL[1]
}
// The version is used to split authURL and container/path
versions := []string{"/v1/", "/v1.0/", "/v2/", "/v2.0/", "/v3/", "/v3.0/", "/v4/", "/v4.0/"}
storageDir := ""
@@ -60,6 +54,17 @@ func CreateSwiftStorage(storageURL string, key string, threads int) (storage *Sw
}
}
// Take out the user name if there is one
if strings.Contains(storageURL, "@") {
// Use regex to split the username and the rest of the URL
lineRegex := regexp.MustCompile(`^(.+)@([^@]+)$`)
match := lineRegex.FindStringSubmatch(storageURL)
if match != nil {
arguments["user"] = match[1]
storageURL = match[2]
}
}
// If no container/path is specified, find them from the arguments
if storageDir == "" {
storageDir = arguments["storage_dir"]