func TestWalk(t *testing.T) { ignores, err := ignore.Load("testdata/.stignore", false) if err != nil { t.Fatal(err) } t.Log(ignores) w := Walker{ Dir: "testdata", BlockSize: 128 * 1024, Matcher: ignores, } fchan, err := w.Walk() if err != nil { t.Fatal(err) } var tmp []protocol.FileInfo for f := range fchan { tmp = append(tmp, f) } sort.Sort(fileList(tmp)) files := fileList(tmp).testfiles() if !reflect.DeepEqual(files, testdata) { t.Errorf("Walk returned unexpected data\nExpected: %v\nActual: %v", testdata, files) } }
func TestWalkSub(t *testing.T) { ignores, err := ignore.Load("testdata/.stignore", false) if err != nil { t.Fatal(err) } w := Walker{ Dir: "testdata", Sub: "dir2", BlockSize: 128 * 1024, Matcher: ignores, } fchan, err := w.Walk() var files []protocol.FileInfo for f := range fchan { files = append(files, f) } if err != nil { t.Fatal(err) } // The directory contains two files, where one is ignored from a higher // level. We should see only the directory and one of the files. if len(files) != 2 { t.Fatalf("Incorrect length %d != 2", len(files)) } if files[0].Name != "dir2" { t.Errorf("Incorrect file %v != dir2", files[0]) } if files[1].Name != filepath.Join("dir2", "cfile") { t.Errorf("Incorrect file %v != dir2/cfile", files[1]) } }
func TestIgnore(t *testing.T) { pats, err := ignore.Load("testdata/.stignore") if err != nil { t.Fatal(err) } var tests = []struct { f string r bool }{ {"afile", false}, {"bfile", true}, {"cfile", false}, {"dfile", false}, {"efile", true}, {"ffile", true}, {"dir1", false}, {filepath.Join("dir1", "cfile"), true}, {filepath.Join("dir1", "dfile"), false}, {filepath.Join("dir1", "efile"), true}, {filepath.Join("dir1", "ffile"), false}, {"dir2", false}, {filepath.Join("dir2", "cfile"), false}, {filepath.Join("dir2", "dfile"), true}, {filepath.Join("dir2", "efile"), true}, {filepath.Join("dir2", "ffile"), false}, {filepath.Join("dir3"), true}, {filepath.Join("dir3", "afile"), true}, } for i, tc := range tests { if r := pats.Match(tc.f); r != tc.r { t.Errorf("Incorrect ignoreFile() #%d (%s); E: %v, A: %v", i, tc.f, tc.r, r) } } }
func (m *Model) AddFolder(cfg config.FolderConfiguration) { if m.started { panic("cannot add folder to started model") } if len(cfg.ID) == 0 { panic("cannot add empty folder id") } m.fmut.Lock() m.folderCfgs[cfg.ID] = cfg m.folderFiles[cfg.ID] = files.NewSet(cfg.ID, m.db) m.folderDevices[cfg.ID] = make([]protocol.DeviceID, len(cfg.Devices)) for i, device := range cfg.Devices { m.folderDevices[cfg.ID][i] = device.DeviceID m.deviceFolders[device.DeviceID] = append(m.deviceFolders[device.DeviceID], cfg.ID) } ignores, _ := ignore.Load(filepath.Join(cfg.Path, ".stignore"), m.cfg.Options().CacheIgnoredFiles) m.folderIgnores[cfg.ID] = ignores m.addedFolder = true m.fmut.Unlock() }
func (m *Model) ScanFolderSub(folder, sub string) error { if p := filepath.Clean(filepath.Join(folder, sub)); !strings.HasPrefix(p, folder) { return errors.New("invalid subpath") } m.fmut.RLock() fs, ok := m.folderFiles[folder] dir := m.folderCfgs[folder].Path ignores, _ := ignore.Load(filepath.Join(dir, ".stignore")) m.folderIgnores[folder] = ignores w := &scanner.Walker{ Dir: dir, Sub: sub, Ignores: ignores, BlockSize: protocol.BlockSize, TempNamer: defTempNamer, CurrentFiler: cFiler{m, folder}, IgnorePerms: m.folderCfgs[folder].IgnorePerms, } m.fmut.RUnlock() if !ok { return errors.New("no such folder") } m.setState(folder, FolderScanning) fchan, err := w.Walk() if err != nil { return err } batchSize := 100 batch := make([]protocol.FileInfo, 0, 00) for f := range fchan { events.Default.Log(events.LocalIndexUpdated, map[string]interface{}{ "folder": folder, "name": f.Name, "modified": time.Unix(f.Modified, 0), "flags": fmt.Sprintf("0%o", f.Flags), "size": f.Size(), }) if len(batch) == batchSize { fs.Update(protocol.LocalDeviceID, batch) batch = batch[:0] } batch = append(batch, f) } if len(batch) > 0 { fs.Update(protocol.LocalDeviceID, batch) } batch = batch[:0] // TODO: We should limit the Have scanning to start at sub seenPrefix := false fs.WithHaveTruncated(protocol.LocalDeviceID, func(fi protocol.FileIntf) bool { f := fi.(protocol.FileInfoTruncated) if !strings.HasPrefix(f.Name, sub) { // Return true so that we keep iterating, until we get to the part // of the tree we are interested in. Then return false so we stop // iterating when we've passed the end of the subtree. return !seenPrefix } seenPrefix = true if !protocol.IsDeleted(f.Flags) { if f.IsInvalid() { return true } if len(batch) == batchSize { fs.Update(protocol.LocalDeviceID, batch) batch = batch[:0] } if ignores.Match(f.Name) { // File has been ignored. Set invalid bit. nf := protocol.FileInfo{ Name: f.Name, Flags: f.Flags | protocol.FlagInvalid, Modified: f.Modified, Version: f.Version, // The file is still the same, so don't bump version } events.Default.Log(events.LocalIndexUpdated, map[string]interface{}{ "folder": folder, "name": f.Name, "modified": time.Unix(f.Modified, 0), "flags": fmt.Sprintf("0%o", f.Flags), "size": f.Size(), }) batch = append(batch, nf) } else if _, err := os.Stat(filepath.Join(dir, f.Name)); err != nil && os.IsNotExist(err) { // File has been deleted nf := protocol.FileInfo{ Name: f.Name, Flags: f.Flags | protocol.FlagDeleted, Modified: f.Modified, Version: lamport.Default.Tick(f.Version), } events.Default.Log(events.LocalIndexUpdated, map[string]interface{}{ "folder": folder, "name": f.Name, "modified": time.Unix(f.Modified, 0), "flags": fmt.Sprintf("0%o", f.Flags), "size": f.Size(), }) batch = append(batch, nf) } } return true }) if len(batch) > 0 { fs.Update(protocol.LocalDeviceID, batch) } m.setState(folder, FolderIdle) return nil }