1
mirror of https://github.com/rclone/rclone synced 2024-12-23 14:23:44 +01:00

operations: fix very long file names when using copy with --partial

Before this change we were using the wrong variable to read the
filename length from. This meant that very long filenames were not
being truncated as intended.

This problem was spotted by Wang Zhiwei on the forum in a code review.

See: https://forum.rclone.org/t/why-use-c-remoteforcopy-instead-of-c-remote-to-check-length-in-copy-operation/45099
This commit is contained in:
Nick Craig-Wood 2024-03-28 12:12:48 +00:00
parent 1cf1f4fab2
commit 7c828ffe09
2 changed files with 45 additions and 2 deletions

View File

@ -98,9 +98,9 @@ func (c *copy) checkPartial() (remoteForCopy string, inplace bool, err error) {
// Avoid making the leaf name longer if it's already lengthy to avoid
// trouble with file name length limits.
suffix := "." + random.String(8) + c.ci.PartialSuffix
base := path.Base(c.remoteForCopy)
base := path.Base(remoteForCopy)
if len(base) > 100 {
remoteForCopy = TruncateString(c.remoteForCopy, len(c.remoteForCopy)-len(suffix)) + suffix
remoteForCopy = TruncateString(remoteForCopy, len(remoteForCopy)-len(suffix)) + suffix
} else {
remoteForCopy += suffix
}

View File

@ -5,6 +5,9 @@ import (
"crypto/rand"
"errors"
"fmt"
"os"
"path"
"sort"
"strings"
"testing"
@ -121,6 +124,46 @@ func TestCopyFile(t *testing.T) {
r.CheckRemoteItems(t, file2)
}
// Find the longest file name for writing to local
func maxLengthFileName(t *testing.T, r *fstest.Run) string {
require.NoError(t, r.Flocal.Mkdir(context.Background(), "")) // create the root
const maxLen = 16 * 1024
name := strings.Repeat("A", maxLen)
i := sort.Search(len(name), func(i int) (fail bool) {
filePath := path.Join(r.LocalName, name[:i])
err := os.WriteFile(filePath, []byte{0}, 0777)
if err != nil {
return true
}
err = os.Remove(filePath)
if err != nil {
t.Logf("Failed to remove test file: %v", err)
}
return false
})
return name[:i-1]
}
// Check we can copy a file of maximum name length
func TestCopyLongFile(t *testing.T) {
ctx := context.Background()
r := fstest.NewRun(t)
if !r.Fremote.Features().IsLocal {
t.Skip("Test only runs on local")
}
// Find the maximum length of file we can write
name := maxLengthFileName(t, r)
t.Logf("Max length of file name is %d", len(name))
file1 := r.WriteFile(name, "file1 contents", t1)
r.CheckLocalItems(t, file1)
err := operations.CopyFile(ctx, r.Fremote, r.Flocal, file1.Path, file1.Path)
require.NoError(t, err)
r.CheckLocalItems(t, file1)
r.CheckRemoteItems(t, file1)
}
func TestCopyFileBackupDir(t *testing.T) {
ctx := context.Background()
ctx, ci := fs.AddConfig(ctx)