lib/versioner: Expand tildes in version directory (fixes #9241) (#9327)

### Purpose

Fix #9241 by expanding tildes in version paths.

When creating the versioner file system, first try to expand any leading
tildes to the user's home directory before handling relative paths. This
makes a version path `"~/p"` expand to `"$HOME/p"` instead of
`"/folder/~/p"`.

### Testing

Added a test to lib/versioner that exercises this code path. Also
manually tested with local syncthing instances.
This commit is contained in:
nf 2024-01-12 20:46:18 +11:00 committed by GitHub
parent 8edd67a569
commit 8b321387c0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 79 additions and 3 deletions

View File

@ -8,7 +8,9 @@ package versioner
import (
"math"
"os"
"path/filepath"
"strings"
"testing"
"time"
@ -93,3 +95,67 @@ func TestSimpleVersioningVersionCount(t *testing.T) {
time.Sleep(time.Second)
}
}
func TestPathTildes(t *testing.T) {
// Test that folder and version paths with leading tildes are expanded
// to the user's home directory. (issue #9241)
home := t.TempDir()
t.Setenv("HOME", home)
if vn := filepath.VolumeName(home); vn != "" {
// Legacy Windows home stuff
t.Setenv("HomeDrive", vn)
t.Setenv("HomePath", strings.TrimPrefix(home, vn))
}
os.Mkdir(filepath.Join(home, "folder"), 0o755)
cfg := config.FolderConfiguration{
FilesystemType: fs.FilesystemTypeBasic,
Path: "~/folder",
Versioning: config.VersioningConfiguration{
FSPath: "~/versions",
FSType: fs.FilesystemTypeBasic,
Params: map[string]string{
"keep": "2",
},
},
}
fs := cfg.Filesystem(nil)
v := newSimple(cfg)
const testPath = "test"
f, err := fs.Create(testPath)
if err != nil {
t.Fatal(err)
}
f.Close()
if err := v.Archive(testPath); err != nil {
t.Fatal(err)
}
// Check that there are no entries in the folder directory; this is
// specifically to check that there is no directory named "~" there.
names, err := fs.DirNames(".")
if err != nil {
t.Fatal(err)
}
if len(names) != 0 {
t.Fatalf("found %d files in folder dir, want 0", len(names))
}
// Check that the versions directory contains one file that begins with
// our test path.
des, err := os.ReadDir(filepath.Join(home, "versions"))
if err != nil {
t.Fatal(err)
}
for _, de := range des {
names = append(names, de.Name())
}
if len(names) != 1 {
t.Fatalf("found %d files in versions dir, want 1", len(names))
}
if got := names[0]; !strings.HasPrefix(got, testPath) {
t.Fatalf("found versioned file %q, want one that begins with %q", got, testPath)
}
}

View File

@ -262,10 +262,20 @@ func versionerFsFromFolderCfg(cfg config.FolderConfiguration) (versionsFs fs.Fil
folderFs := cfg.Filesystem(nil)
if cfg.Versioning.FSPath == "" {
versionsFs = fs.NewFilesystem(folderFs.Type(), filepath.Join(folderFs.URI(), DefaultPath))
} else if cfg.Versioning.FSType == fs.FilesystemTypeBasic && !filepath.IsAbs(cfg.Versioning.FSPath) {
// We only know how to deal with relative folders for basic filesystems, as that's the only one we know
} else if cfg.Versioning.FSType == fs.FilesystemTypeBasic {
// Expand any leading tildes for basic filesystems,
// before checking for absolute paths.
path, err := fs.ExpandTilde(cfg.Versioning.FSPath)
if err != nil {
path = cfg.Versioning.FSPath
}
// We only know how to deal with relative folders for
// basic filesystems, as that's the only one we know
// how to check if it's absolute or relative.
versionsFs = fs.NewFilesystem(cfg.Versioning.FSType, filepath.Join(folderFs.URI(), cfg.Versioning.FSPath))
if !filepath.IsAbs(path) {
path = filepath.Join(folderFs.URI(), path)
}
versionsFs = fs.NewFilesystem(cfg.Versioning.FSType, path)
} else {
versionsFs = fs.NewFilesystem(cfg.Versioning.FSType, cfg.Versioning.FSPath)
}