func (st *State) Sync(name string, add [][]byte, del []string) ([][]byte, error) { mgr := st.Managers[name] if mgr == nil || mgr.Connected.IsZero() { return nil, fmt.Errorf("unconnected manager %v", name) } if len(del) != 0 { for _, h := range del { sig, err := hash.FromString(h) if err != nil { Logf(0, "manager %v: bad hash: %v", mgr.name, h) continue } delete(mgr.Corpus, sig) } st.purgeCorpus() } if len(add) != 0 { st.seq++ for _, prog := range add { st.addInput(mgr, prog) } } inputs, err := st.pendingInputs(mgr) mgr.Added += len(add) mgr.Deleted += len(del) mgr.New += len(inputs) return inputs, err }
func newPersistentSet(dir string, verify func(data []byte) bool) *PersistentSet { ps := &PersistentSet{ dir: dir, m: make(map[hash.Sig][]byte), } os.MkdirAll(dir, 0770) filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { if err != nil { Fatalf("error during dir walk: %v\n", err) } if info.IsDir() { if info.Name() == ".git" { return filepath.SkipDir // in case corpus is checked in } return nil } data, err := ioutil.ReadFile(path) if err != nil { Fatalf("error during file read: %v\n", err) return nil } sig := hash.Hash(data) if _, ok := ps.m[sig]; ok { return nil } name := info.Name() if len(data) == 0 { // This can happen is master runs on machine-under-test, // and it has crashed midway. Logf(0, "removing empty file %v", name) os.Remove(path) return nil } if _, err := hash.FromString(name); err != nil { Logf(0, "unknown file in persistent dir %v: %v", dir, name) return nil } if verify != nil && !verify(data) { os.Remove(path) return nil } if name != sig.String() { Logf(0, "bad hash in persistent dir %v for file %v, expect %v", dir, name, sig.String()) if err := ioutil.WriteFile(filepath.Join(ps.dir, sig.String()), data, 0660); err != nil { Fatalf("failed to write file: %v", err) } os.Remove(path) } ps.m[sig] = data ps.a = append(ps.a, data) return nil }) return ps }
// Make creates State and initializes it from dir. func Make(dir string) (*State, error) { st := &State{ dir: dir, Corpus: make(map[hash.Sig]*Input), Managers: make(map[string]*Manager), } corpusDir := filepath.Join(st.dir, "corpus") os.MkdirAll(corpusDir, 0700) inputs, err := ioutil.ReadDir(corpusDir) if err != nil { return nil, fmt.Errorf("failed to read %v dir: %v", corpusDir, err) } for _, inp := range inputs { data, err := ioutil.ReadFile(filepath.Join(corpusDir, inp.Name())) if err != nil { return nil, err } if _, err := prog.CallSet(data); err != nil { return nil, err } parts := strings.Split(inp.Name(), "-") if len(parts) != 2 { return nil, fmt.Errorf("bad file in corpus: %v", inp.Name()) } seq, err := strconv.ParseUint(parts[1], 10, 64) if err != nil { return nil, fmt.Errorf("bad file in corpus: %v", inp.Name()) } sig := hash.Hash(data) if sig.String() != parts[0] { return nil, fmt.Errorf("bad file in corpus: %v, want hash %v", inp.Name(), sig.String()) } st.Corpus[sig] = &Input{ seq: seq, prog: data, } if st.seq < seq { st.seq = seq } } managersDir := filepath.Join(st.dir, "manager") os.MkdirAll(managersDir, 0700) managers, err := ioutil.ReadDir(managersDir) if err != nil { return nil, fmt.Errorf("failed to read %v dir: %v", managersDir, err) } for _, manager := range managers { mgr := &Manager{ name: manager.Name(), } st.Managers[mgr.name] = mgr mgr.dir = filepath.Join(managersDir, mgr.name) seqStr, _ := ioutil.ReadFile(filepath.Join(mgr.dir, "seq")) mgr.seq, _ = strconv.ParseUint(string(seqStr), 10, 64) if st.seq < mgr.seq { st.seq = mgr.seq } mgr.Corpus = make(map[hash.Sig]bool) corpusDir := filepath.Join(mgr.dir, "corpus") os.MkdirAll(corpusDir, 0700) corpus, err := ioutil.ReadDir(corpusDir) if err != nil { return nil, fmt.Errorf("failed to read %v dir: %v", corpusDir, err) } for _, input := range corpus { sig, err := hash.FromString(input.Name()) if err != nil { return nil, fmt.Errorf("bad file in corpus: %v", input.Name()) } mgr.Corpus[sig] = true } } return st, err }