lib/config: Support symlinked root (fixes #4542, fixes #4353)

GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4545
LGTM: imsodin, calmh
This commit is contained in:
Audrius Butkevicius 2017-11-26 07:51:22 +00:00 committed by Jakob Borg
parent 429b3a0429
commit 95a65bf0d0
2 changed files with 78 additions and 3 deletions

View File

@ -10,6 +10,7 @@ import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"reflect" "reflect"
@ -20,6 +21,7 @@ import (
"github.com/d4l3k/messagediff" "github.com/d4l3k/messagediff"
"github.com/syncthing/syncthing/lib/fs" "github.com/syncthing/syncthing/lib/fs"
"github.com/syncthing/syncthing/lib/osutil"
"github.com/syncthing/syncthing/lib/protocol" "github.com/syncthing/syncthing/lib/protocol"
) )
@ -430,6 +432,62 @@ func TestFolderPath(t *testing.T) {
} }
} }
func TestFolderCheckPath(t *testing.T) {
n, err := ioutil.TempDir("", "")
if err != nil {
t.Fatal(err)
}
err = os.MkdirAll(filepath.Join(n, "dir", ".stfolder"), os.FileMode(0777))
if err != nil {
t.Fatal(err)
}
testcases := []struct {
path string
err error
}{
{
path: "",
err: errMarkerMissing,
},
{
path: "does not exist",
err: errPathMissing,
},
{
path: "dir",
err: nil,
},
}
err = osutil.DebugSymlinkForTestsOnly(filepath.Join(n, "dir"), filepath.Join(n, "link"))
if err == nil {
t.Log("running with symlink check")
testcases = append(testcases, struct {
path string
err error
}{
path: "link",
err: nil,
})
} else if runtime.GOOS != "windows" {
t.Log("running without symlink check")
t.Fatal(err)
}
for _, testcase := range testcases {
cfg := FolderConfiguration{
Path: filepath.Join(n, testcase.path),
MarkerName: DefaultMarkerName,
}
if err := cfg.CheckPath(); testcase.err != err {
t.Errorf("unexpected error in case %s: %s != %s", testcase.path, err, testcase.err)
}
}
}
func TestNewSaveLoad(t *testing.T) { func TestNewSaveLoad(t *testing.T) {
path := "testdata/temp.xml" path := "testdata/temp.xml"
os.Remove(path) os.Remove(path)

View File

@ -16,8 +16,9 @@ import (
) )
var ( var (
errPathMissing = errors.New("folder path missing") errPathNotDirectory = errors.New("folder path not a directory")
errMarkerMissing = errors.New("folder marker missing") errPathMissing = errors.New("folder path missing")
errMarkerMissing = errors.New("folder marker missing")
) )
const DefaultMarkerName = ".stfolder" const DefaultMarkerName = ".stfolder"
@ -124,12 +125,28 @@ func (f *FolderConfiguration) CreateMarker() error {
// CheckPath returns nil if the folder root exists and contains the marker file // CheckPath returns nil if the folder root exists and contains the marker file
func (f *FolderConfiguration) CheckPath() error { func (f *FolderConfiguration) CheckPath() error {
fi, err := f.Filesystem().Stat(".") fi, err := f.Filesystem().Stat(".")
if err != nil || !fi.IsDir() { if err != nil {
if !fs.IsNotExist(err) {
return err
}
return errPathMissing return errPathMissing
} }
// Users might have the root directory as a symlink or reparse point.
// Furthermore, OneDrive bullcrap uses a magic reparse point to the cloudz...
// Yet it's impossible for this to happen, as filesystem adds a trailing
// path separator to the root, so even if you point the filesystem at a file
// Stat ends up calling stat on C:\dir\file\ which, fails with "is not a directory"
// in the error check above, and we don't even get to here.
if !fi.IsDir() && !fi.IsSymlink() {
return errPathNotDirectory
}
_, err = f.Filesystem().Stat(f.MarkerName) _, err = f.Filesystem().Stat(f.MarkerName)
if err != nil { if err != nil {
if !fs.IsNotExist(err) {
return err
}
return errMarkerMissing return errMarkerMissing
} }