Paths are joined with client side separators when targeting remotes (#547)

Currently, filepath.Join is used to join path fragments that are supposed
to be created on remote storage backends. This could theoretically cause
problems when the separators used by the client and the remotes do not match.
It's unlikely this causes problems right now, but it's definitely better to
rectify it before it causes further confusion.

This was raised in #541
This commit is contained in:
Frederik Ring
2025-02-27 13:55:14 +01:00
committed by GitHub
parent d8ac5ae7e6
commit eb4099debd
5 changed files with 11 additions and 14 deletions

View File

@@ -9,6 +9,7 @@ import (
"errors"
"fmt"
"os"
"path"
"path/filepath"
"strings"
"sync"
@@ -128,7 +129,7 @@ func (b *azureBlobStorage) Copy(file string) error {
_, err = b.client.UploadStream(
context.Background(),
b.containerName,
filepath.Join(b.DestinationPath, filepath.Base(file)),
path.Join(b.DestinationPath, filepath.Base(file)),
fileReader,
b.uploadStreamOptions,
)
@@ -141,7 +142,7 @@ func (b *azureBlobStorage) Copy(file string) error {
// Prune rotates away backups according to the configuration and provided
// deadline for the Azure Blob storage backend.
func (b *azureBlobStorage) Prune(deadline time.Time, pruningPrefix string) (*storage.PruneStats, error) {
lookupPrefix := filepath.Join(b.DestinationPath, pruningPrefix)
lookupPrefix := path.Join(b.DestinationPath, pruningPrefix)
pager := b.client.NewListBlobsFlatPager(b.containerName, &container.ListBlobsFlatOptions{
Prefix: &lookupPrefix,
})

View File

@@ -7,7 +7,6 @@ import (
"net/url"
"os"
"path"
"path/filepath"
"strings"
"sync"
"time"
@@ -195,7 +194,7 @@ loop:
_, err = b.client.UploadSessionFinish(
files.NewUploadSessionFinishArg(
files.NewUploadSessionCursor(sessionId, 0),
files.NewCommitInfo(filepath.Join(b.DestinationPath, name)),
files.NewCommitInfo(path.Join(b.DestinationPath, name)),
), nil)
if err != nil {
return errwrap.Wrap(err, "error finishing the upload session")
@@ -247,7 +246,7 @@ func (b *dropboxStorage) Prune(deadline time.Time, pruningPrefix string) (*stora
pruneErr := b.DoPrune(b.Name(), len(matches), lenCandidates, deadline, func() error {
for _, match := range matches {
if _, err := b.client.DeleteV2(files.NewDeleteArg(filepath.Join(b.DestinationPath, match.Name))); err != nil {
if _, err := b.client.DeleteV2(files.NewDeleteArg(path.Join(b.DestinationPath, match.Name))); err != nil {
return errwrap.Wrap(err, "error removing file from Dropbox storage")
}
}

View File

@@ -10,7 +10,6 @@ import (
"fmt"
"os"
"path"
"path/filepath"
"time"
"github.com/minio/minio-go/v7"
@@ -124,7 +123,7 @@ func (b *s3Storage) Copy(file string) error {
putObjectOptions.PartSize = uint64(partSize)
}
if _, err := b.client.FPutObject(context.Background(), b.bucket, filepath.Join(b.DestinationPath, name), file, putObjectOptions); err != nil {
if _, err := b.client.FPutObject(context.Background(), b.bucket, path.Join(b.DestinationPath, name), file, putObjectOptions); err != nil {
if errResp := minio.ToErrorResponse(err); errResp.Message != "" {
return errwrap.Wrap(
nil,
@@ -147,7 +146,7 @@ func (b *s3Storage) Copy(file string) error {
// Prune rotates away backups according to the configuration and provided deadline for the S3/Minio storage backend.
func (b *s3Storage) Prune(deadline time.Time, pruningPrefix string) (*storage.PruneStats, error) {
candidates := b.client.ListObjects(context.Background(), b.bucket, minio.ListObjectsOptions{
Prefix: filepath.Join(b.DestinationPath, pruningPrefix),
Prefix: path.Join(b.DestinationPath, pruningPrefix),
Recursive: true,
})

View File

@@ -8,7 +8,6 @@ import (
"io"
"os"
"path"
"path/filepath"
"strings"
"time"
@@ -115,7 +114,7 @@ func (b *sshStorage) Copy(file string) error {
}
defer source.Close()
destination, err := b.sftpClient.Create(filepath.Join(b.DestinationPath, name))
destination, err := b.sftpClient.Create(path.Join(b.DestinationPath, name))
if err != nil {
return errwrap.Wrap(err, "error creating file")
}
@@ -180,7 +179,7 @@ func (b *sshStorage) Prune(deadline time.Time, pruningPrefix string) (*storage.P
pruneErr := b.DoPrune(b.Name(), len(matches), len(candidates), deadline, func() error {
for _, match := range matches {
if err := b.sftpClient.Remove(filepath.Join(b.DestinationPath, match)); err != nil {
if err := b.sftpClient.Remove(path.Join(b.DestinationPath, match)); err != nil {
return errwrap.Wrap(err, "error removing file")
}
}

View File

@@ -9,7 +9,6 @@ import (
"net/http"
"os"
"path"
"path/filepath"
"strings"
"time"
@@ -77,7 +76,7 @@ func (b *webDavStorage) Copy(file string) error {
return errwrap.Wrap(err, "error opening the file to be uploaded")
}
if err := b.client.WriteStream(filepath.Join(b.DestinationPath, name), r, 0644); err != nil {
if err := b.client.WriteStream(path.Join(b.DestinationPath, name), r, 0644); err != nil {
return errwrap.Wrap(err, "error uploading the file")
}
b.Log(storage.LogLevelInfo, b.Name(), "Uploaded a copy of backup '%s' to '%s' at path '%s'.", file, b.url, b.DestinationPath)
@@ -110,7 +109,7 @@ func (b *webDavStorage) Prune(deadline time.Time, pruningPrefix string) (*storag
pruneErr := b.DoPrune(b.Name(), len(matches), lenCandidates, deadline, func() error {
for _, match := range matches {
if err := b.client.Remove(filepath.Join(b.DestinationPath, match.Name())); err != nil {
if err := b.client.Remove(path.Join(b.DestinationPath, match.Name())); err != nil {
return errwrap.Wrap(err, "error removing file")
}
}