From 9752ea9ac30cd056866ef47991ed9a1116339928 Mon Sep 17 00:00:00 2001 From: Jakob Borg Date: Mon, 11 Aug 2014 20:20:01 +0200 Subject: [PATCH] Implement external scan request (fixes #9) --- cmd/syncthing/gui.go | 11 +++++++++++ model/model.go | 21 ++++++++++++++++++++- scanner/walk.go | 6 ++++-- scanner/walk_test.go | 24 ++++++++++++++++++++++++ 4 files changed, 59 insertions(+), 3 deletions(-) diff --git a/cmd/syncthing/gui.go b/cmd/syncthing/gui.go index 45120f567..a49d68be2 100644 --- a/cmd/syncthing/gui.go +++ b/cmd/syncthing/gui.go @@ -126,6 +126,7 @@ func startGUI(cfg config.GUIConfiguration, assetDir string, m *model.Model) erro postRestMux.HandleFunc("/rest/restart", restPostRestart) postRestMux.HandleFunc("/rest/shutdown", restPostShutdown) postRestMux.HandleFunc("/rest/upgrade", restPostUpgrade) + postRestMux.HandleFunc("/rest/scan", withModel(m, restPostScan)) // A handler that splits requests between the two above and disables // caching @@ -530,6 +531,16 @@ func restPostUpgrade(w http.ResponseWriter, r *http.Request) { } } +func restPostScan(m *model.Model, w http.ResponseWriter, r *http.Request) { + qs := r.URL.Query() + repo := qs.Get("repo") + sub := qs.Get("sub") + err := m.ScanRepoSub(repo, sub) + if err != nil { + http.Error(w, err.Error(), 500) + } +} + func getQR(w http.ResponseWriter, r *http.Request) { var qs = r.URL.Query() var text = qs.Get("text") diff --git a/model/model.go b/model/model.go index f1e2cb113..99f530904 100644 --- a/model/model.go +++ b/model/model.go @@ -12,6 +12,7 @@ import ( "os" "path/filepath" "strconv" + "strings" "sync" "time" @@ -744,12 +745,21 @@ func (m *Model) CleanRepos() { } func (m *Model) ScanRepo(repo string) error { + return m.ScanRepoSub(repo, "") +} + +func (m *Model) ScanRepoSub(repo, sub string) error { + if p := filepath.Clean(filepath.Join(repo, sub)); !strings.HasPrefix(p, repo) { + return errors.New("invalid subpath") + } + m.rmut.RLock() - fs := m.repoFiles[repo] + fs, ok := m.repoFiles[repo] dir := m.repoCfgs[repo].Directory w := &scanner.Walker{ Dir: dir, + Sub: sub, IgnoreFile: ".stignore", BlockSize: scanner.StandardBlockSize, TempNamer: defTempNamer, @@ -758,6 +768,9 @@ func (m *Model) ScanRepo(repo string) error { IgnorePerms: m.repoCfgs[repo].IgnorePerms, } m.rmut.RUnlock() + if !ok { + return errors.New("no such repo") + } m.setState(repo, RepoScanning) fchan, _, err := w.Walk() @@ -786,7 +799,13 @@ func (m *Model) ScanRepo(repo string) error { } batch = batch[:0] + // TODO: We should limit the Have scanning to start at sub + seenPrefix := false fs.WithHave(protocol.LocalNodeID, func(f protocol.FileInfo) bool { + if !strings.HasPrefix(f.Name, sub) { + return !seenPrefix + } + seenPrefix = true if !protocol.IsDeleted(f.Flags) { if len(batch) == batchSize { fs.Update(protocol.LocalNodeID, batch) diff --git a/scanner/walk.go b/scanner/walk.go index a88b04ebc..94e1c5921 100644 --- a/scanner/walk.go +++ b/scanner/walk.go @@ -22,6 +22,8 @@ import ( type Walker struct { // Dir is the base directory for the walk Dir string + // Limit walking to this path within Dir, or no limit if Sub is blank + Sub string // BlockSize controls the size of the block used when hashing. BlockSize int // If IgnoreFile is not empty, it is the name used for the file that holds ignore patterns. @@ -61,7 +63,7 @@ type CurrentFiler interface { // file system. Files are blockwise hashed. func (w *Walker) Walk() (chan protocol.FileInfo, map[string][]string, error) { if debug { - l.Debugln("Walk", w.Dir, w.BlockSize, w.IgnoreFile) + l.Debugln("Walk", w.Dir, w.Sub, w.BlockSize, w.IgnoreFile) } err := checkDir(w.Dir) @@ -77,7 +79,7 @@ func (w *Walker) Walk() (chan protocol.FileInfo, map[string][]string, error) { go func() { filepath.Walk(w.Dir, w.loadIgnoreFiles(w.Dir, ignore)) - filepath.Walk(w.Dir, hashFiles) + filepath.Walk(filepath.Join(w.Dir, w.Sub), hashFiles) close(files) }() diff --git a/scanner/walk_test.go b/scanner/walk_test.go index 5f9538725..32a54960b 100644 --- a/scanner/walk_test.go +++ b/scanner/walk_test.go @@ -29,6 +29,30 @@ var correctIgnores = map[string][]string{ ".": {".*", "quux"}, } +func TestWalkSub(t *testing.T) { + w := Walker{ + Dir: "testdata", + Sub: "foo", + BlockSize: 128 * 1024, + IgnoreFile: ".stignore", + } + fchan, _, err := w.Walk() + var files []protocol.FileInfo + for f := range fchan { + files = append(files, f) + } + if err != nil { + t.Fatal(err) + } + + if len(files) != 1 { + t.Fatalf("Incorrect length %d != 1", len(files)) + } + if files[0].Name != "foo" { + t.Errorf("Incorrect file %v != foo", files[0]) + } +} + func TestWalk(t *testing.T) { w := Walker{ Dir: "testdata",