예제 #1
0
func packIDTester(repo *repository.Repository, inChan <-chan backend.ID, errChan chan<- error, wg *sync.WaitGroup, done <-chan struct{}) {
	debug.Log("Checker.testPackID", "worker start")
	defer debug.Log("Checker.testPackID", "worker done")

	defer wg.Done()

	for id := range inChan {
		ok, err := repo.Backend().Test(backend.Data, id.String())
		if err != nil {
			err = PackError{ID: id, Err: err}
		} else {
			if !ok {
				err = PackError{ID: id, Err: errors.New("does not exist")}
			}
		}

		if err != nil {
			debug.Log("Checker.testPackID", "error checking for pack %s: %v", id.Str(), err)
			select {
			case <-done:
				return
			case errChan <- err:
			}

			continue
		}

		debug.Log("Checker.testPackID", "pack %s exists", id.Str())
	}
}
예제 #2
0
파일: cmd_backup.go 프로젝트: fawick/restic
func findLatestSnapshot(repo *repository.Repository, targets []string) (backend.ID, error) {
	var (
		latest   time.Time
		latestID backend.ID
		found    bool
	)

	for snapshotID := range repo.List(backend.Snapshot, make(chan struct{})) {
		snapshot, err := restic.LoadSnapshot(repo, snapshotID)
		if err != nil {
			return backend.ID{}, fmt.Errorf("Error listing snapshot: %v", err)
		}
		if snapshot.Time.After(latest) && samePaths(snapshot.Paths, targets) {
			latest = snapshot.Time
			latestID = snapshotID
			found = true
		}
	}

	if !found {
		return backend.ID{}, errNoSnapshotFound
	}

	return latestID, nil
}
예제 #3
0
func printTrees(repo *repository.Repository, wr io.Writer) error {
	done := make(chan struct{})
	defer close(done)

	trees := []backend.ID{}

	for _, idx := range repo.Index().All() {
		for blob := range idx.Each(nil) {
			if blob.Type != pack.Tree {
				continue
			}

			trees = append(trees, blob.ID)
		}
	}

	for _, id := range trees {
		tree, err := restic.LoadTree(repo, id)
		if err != nil {
			fmt.Fprintf(os.Stderr, "LoadTree(%v): %v", id.Str(), err)
			continue
		}

		fmt.Fprintf(wr, "tree_id: %v\n", id)

		prettyPrintJSON(wr, tree)
	}

	return nil
}
예제 #4
0
파일: cmd_key.go 프로젝트: ckemper67/restic
func listKeys(s *repository.Repository) error {
	tab := NewTable()
	tab.Header = fmt.Sprintf(" %-10s  %-10s  %-10s  %s", "ID", "User", "Host", "Created")
	tab.RowFormat = "%s%-10s  %-10s  %-10s  %s"

	done := make(chan struct{})
	defer close(done)

	for id := range s.List(restic.KeyFile, done) {
		k, err := repository.LoadKey(s, id.String())
		if err != nil {
			Warnf("LoadKey() failed: %v\n", err)
			continue
		}

		var current string
		if id.String() == s.KeyName() {
			current = "*"
		} else {
			current = " "
		}
		tab.Rows = append(tab.Rows, []interface{}{current, id.Str(),
			k.Username, k.Hostname, k.Created.Format(TimeFormat)})
	}

	return tab.Write(globalOptions.stdout)
}
예제 #5
0
파일: node.go 프로젝트: fawick/restic
func (node Node) createFileAt(path string, repo *repository.Repository) error {
	f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, 0600)
	defer f.Close()

	if err != nil {
		return errors.Annotate(err, "OpenFile")
	}

	var buf []byte
	for _, id := range node.Content {
		blob, err := repo.Index().Lookup(id)
		if err != nil {
			return err
		}

		buf = buf[:cap(buf)]
		if uint(len(buf)) < blob.Length {
			buf = make([]byte, blob.Length)
		}

		buf, err := repo.LoadBlob(pack.Data, id, buf)
		if err != nil {
			return errors.Annotate(err, "Load")
		}

		_, err = f.Write(buf)
		if err != nil {
			return errors.Annotate(err, "Write")
		}
	}

	return nil
}
예제 #6
0
// saveTree saves a tree of fake files in the repo and returns the ID.
func saveTree(t testing.TB, repo *repository.Repository, seed int64) backend.ID {
	rnd := rand.NewSource(seed)
	numNodes := int(rnd.Int63() % 64)
	t.Logf("create %v nodes", numNodes)

	var tree Tree
	for i := 0; i < numNodes; i++ {
		seed := rnd.Int63() % maxSeed
		size := rnd.Int63() % maxFileSize

		node := &Node{
			Name: fmt.Sprintf("file-%v", seed),
			Type: "file",
			Mode: 0644,
			Size: uint64(size),
		}

		node.Content = saveFile(t, repo, fakeFile(t, seed, size))
		tree.Nodes = append(tree.Nodes, node)
	}

	id, err := repo.SaveJSON(pack.Tree, tree)
	if err != nil {
		t.Fatal(err)
	}

	return id
}
예제 #7
0
func loadBlob(t *testing.T, repo *repository.Repository, id backend.ID, buf []byte) []byte {
	buf, err := repo.LoadBlob(pack.Data, id, buf)
	if err != nil {
		t.Fatalf("LoadBlob(%v) returned error %v", id, err)
	}

	return buf
}
예제 #8
0
func listIndexIDs(repo *repository.Repository) (list backend.IDs) {
	done := make(chan struct{})
	for id := range repo.List(backend.Index, done) {
		list = append(list, id)
	}

	return list
}
예제 #9
0
파일: lock_test.go 프로젝트: fawick/restic
func createFakeLock(repo *repository.Repository, t time.Time, pid int) (backend.ID, error) {
	hostname, err := os.Hostname()
	if err != nil {
		return backend.ID{}, err
	}

	newLock := &restic.Lock{Time: t, PID: pid, Hostname: hostname}
	return repo.SaveJSONUnpacked(backend.Lock, &newLock)
}
예제 #10
0
파일: lock.go 프로젝트: fawick/restic
// LoadLock loads and unserializes a lock from a repository.
func LoadLock(repo *repository.Repository, id backend.ID) (*Lock, error) {
	lock := &Lock{}
	if err := repo.LoadJSONUnpacked(backend.Lock, id, lock); err != nil {
		return nil, err
	}
	lock.lockID = &id

	return lock, nil
}
예제 #11
0
파일: snapshot.go 프로젝트: fawick/restic
// FindSnapshot takes a string and tries to find a snapshot whose ID matches
// the string as closely as possible.
func FindSnapshot(repo *repository.Repository, s string) (backend.ID, error) {
	// find snapshot id with prefix
	name, err := backend.Find(repo.Backend(), backend.Snapshot, s)
	if err != nil {
		return backend.ID{}, err
	}

	return backend.ParseID(name)
}
예제 #12
0
파일: snapshot.go 프로젝트: fawick/restic
func LoadSnapshot(repo *repository.Repository, id backend.ID) (*Snapshot, error) {
	sn := &Snapshot{id: &id}
	err := repo.LoadJSONUnpacked(backend.Snapshot, id, sn)
	if err != nil {
		return nil, err
	}

	return sn, nil
}
예제 #13
0
파일: cmd_key.go 프로젝트: fawick/restic
func (cmd CmdKey) addKey(repo *repository.Repository) error {
	id, err := repository.AddKey(repo, cmd.getNewPassword(), repo.Key())
	if err != nil {
		return fmt.Errorf("creating new key failed: %v\n", err)
	}

	cmd.global.Verbosef("saved new key as %s\n", id)

	return nil
}
예제 #14
0
func list(repo *repository.Repository, t backend.Type) (IDs []string) {
	done := make(chan struct{})
	defer close(done)

	for id := range repo.List(t, done) {
		IDs = append(IDs, id.String())
	}

	return IDs
}
예제 #15
0
파일: repacker.go 프로젝트: fawick/restic
// FindBlobsForPacks returns the set of blobs contained in a pack of packs.
func FindBlobsForPacks(repo *repository.Repository, packs backend.IDSet) (backend.IDSet, error) {
	blobs := backend.NewIDSet()

	for packID := range packs {
		for _, packedBlob := range repo.Index().ListPack(packID) {
			blobs.Insert(packedBlob.ID)
		}
	}

	return blobs, nil
}
예제 #16
0
// saveRandomDataBlobs generates random data blobs and saves them to the repository.
func saveRandomDataBlobs(t testing.TB, repo *repository.Repository, num int, sizeMax int) {
	for i := 0; i < num; i++ {
		size := mrand.Int() % sizeMax

		buf := make([]byte, size)
		_, err := io.ReadFull(rand.Reader, buf)
		OK(t, err)

		_, err = repo.SaveAndEncrypt(pack.Data, buf, nil)
		OK(t, err)
	}
}
예제 #17
0
파일: backend.go 프로젝트: fawick/restic
func TeardownRepo(repo *repository.Repository) {
	if !TestCleanupTempDirs {
		l := repo.Backend().(*local.Local)
		fmt.Printf("leaving local backend at %s\n", l.Location())
		return
	}

	err := repo.Delete()
	if err != nil {
		panic(err)
	}
}
예제 #18
0
파일: cmd_key.go 프로젝트: ckemper67/restic
func deleteKey(repo *repository.Repository, name string) error {
	if name == repo.KeyName() {
		return errors.Fatal("refusing to remove key currently used to access repository")
	}

	err := repo.Backend().Remove(restic.KeyFile, name)
	if err != nil {
		return err
	}

	Verbosef("removed key %v\n", name)
	return nil
}
예제 #19
0
파일: cmd_key.go 프로젝트: fawick/restic
func (cmd CmdKey) deleteKey(repo *repository.Repository, name string) error {
	if name == repo.KeyName() {
		return errors.New("refusing to remove key currently used to access repository")
	}

	err := repo.Backend().Remove(backend.Key, name)
	if err != nil {
		return err
	}

	cmd.global.Verbosef("removed key %v\n", name)
	return nil
}
예제 #20
0
파일: lock.go 프로젝트: fawick/restic
// RemoveStaleLocks deletes all locks detected as stale from the repository.
func RemoveStaleLocks(repo *repository.Repository) error {
	return eachLock(repo, func(id backend.ID, lock *Lock, err error) error {
		// ignore locks that cannot be loaded
		if err != nil {
			return nil
		}

		if lock.Stale() {
			return repo.Backend().Remove(backend.Lock, id.String())
		}

		return nil
	})
}
예제 #21
0
파일: lock.go 프로젝트: fawick/restic
func eachLock(repo *repository.Repository, f func(backend.ID, *Lock, error) error) error {
	done := make(chan struct{})
	defer close(done)

	for id := range repo.List(backend.Lock, done) {
		lock, err := LoadLock(repo, id)
		err = f(id, lock, err)
		if err != nil {
			return err
		}
	}

	return nil
}
예제 #22
0
파일: repacker.go 프로젝트: fawick/restic
// FindPacksForBlobs returns the set of packs that contain the blobs.
func FindPacksForBlobs(repo *repository.Repository, blobs backend.IDSet) (backend.IDSet, error) {
	packs := backend.NewIDSet()
	idx := repo.Index()
	for id := range blobs {
		blob, err := idx.Lookup(id)
		if err != nil {
			return nil, err
		}

		packs.Insert(blob.PackID)
	}

	return packs, nil
}
예제 #23
0
파일: cmd_key.go 프로젝트: ckemper67/restic
func addKey(gopts GlobalOptions, repo *repository.Repository) error {
	pw, err := getNewPassword(gopts)
	if err != nil {
		return err
	}

	id, err := repository.AddKey(repo, pw, repo.Key())
	if err != nil {
		return errors.Fatalf("creating new key failed: %v\n", err)
	}

	Verbosef("saved new key as %s\n", id)

	return nil
}
예제 #24
0
// saveTreeJSON stores a tree in the repository.
func saveTreeJSON(repo *repository.Repository, item interface{}) (backend.ID, error) {
	data, err := json.Marshal(item)
	if err != nil {
		return backend.ID{}, err
	}
	data = append(data, '\n')

	// check if tree has been saved before
	id := backend.Hash(data)
	if repo.Index().Has(id) {
		return id, nil
	}

	return repo.SaveJSON(pack.Tree, item)
}
예제 #25
0
파일: repacker.go 프로젝트: fawick/restic
// RepackBlobs reads all blobs in blobIDs from src and saves them into new pack
// files in dst. Source and destination repo may be the same.
func RepackBlobs(src, dst *repository.Repository, blobIDs backend.IDSet) (err error) {
	for id := range blobIDs {
		err = repackBlob(src, dst, id)
		if err != nil {
			return err
		}
	}

	err = dst.Flush()
	if err != nil {
		return err
	}

	return nil
}
예제 #26
0
// LoadAllSnapshots returns a list of all snapshots in the repo.
func LoadAllSnapshots(repo *repository.Repository) (snapshots []*Snapshot, err error) {
	done := make(chan struct{})
	defer close(done)

	for id := range repo.List(backend.Snapshot, done) {
		sn, err := LoadSnapshot(repo, id)
		if err != nil {
			return nil, err
		}

		snapshots = append(snapshots, sn)
	}

	return snapshots, nil
}
예제 #27
0
func findInTree(repo *repository.Repository, pat findPattern, id restic.ID, path string) ([]findResult, error) {
	debug.Log("checking tree %v\n", id)
	tree, err := repo.LoadTree(id)
	if err != nil {
		return nil, err
	}

	results := []findResult{}
	for _, node := range tree.Nodes {
		debug.Log("  testing entry %q\n", node.Name)

		m, err := filepath.Match(pat.pattern, node.Name)
		if err != nil {
			return nil, err
		}

		if m {
			debug.Log("    pattern matches\n")
			if !pat.oldest.IsZero() && node.ModTime.Before(pat.oldest) {
				debug.Log("    ModTime is older than %s\n", pat.oldest)
				continue
			}

			if !pat.newest.IsZero() && node.ModTime.After(pat.newest) {
				debug.Log("    ModTime is newer than %s\n", pat.newest)
				continue
			}

			results = append(results, findResult{node: node, path: path})
		} else {
			debug.Log("    pattern does not match\n")
		}

		if node.Type == "dir" {
			subdirResults, err := findInTree(repo, pat, *node.Subtree, filepath.Join(path, node.Name))
			if err != nil {
				return nil, err
			}

			results = append(results, subdirResults...)
		}
	}

	return results, nil
}
예제 #28
0
파일: cmd_ls.go 프로젝트: restic/restic
func printTree(prefix string, repo *repository.Repository, id restic.ID) error {
	tree, err := repo.LoadTree(id)
	if err != nil {
		return err
	}

	for _, entry := range tree.Nodes {
		Printf(printNode(prefix, entry) + "\n")

		if entry.Type == "dir" && entry.Subtree != nil {
			err = printTree(filepath.Join(prefix, entry.Name), repo, *entry.Subtree)
			if err != nil {
				return err
			}
		}
	}

	return nil
}
예제 #29
0
// loadSnapshotTreeIDs loads all snapshots from backend and returns the tree IDs.
func loadSnapshotTreeIDs(repo *repository.Repository) (backend.IDs, []error) {
	var trees struct {
		IDs backend.IDs
		sync.Mutex
	}

	var errs struct {
		errs []error
		sync.Mutex
	}

	snapshotWorker := func(strID string, done <-chan struct{}) error {
		id, err := backend.ParseID(strID)
		if err != nil {
			return err
		}

		debug.Log("Checker.Snaphots", "load snapshot %v", id.Str())

		treeID, err := loadTreeFromSnapshot(repo, id)
		if err != nil {
			errs.Lock()
			errs.errs = append(errs.errs, err)
			errs.Unlock()
			return nil
		}

		debug.Log("Checker.Snaphots", "snapshot %v has tree %v", id.Str(), treeID.Str())
		trees.Lock()
		trees.IDs = append(trees.IDs, treeID)
		trees.Unlock()

		return nil
	}

	err := repository.FilesInParallel(repo.Backend(), backend.Snapshot, defaultParallelism, snapshotWorker)
	if err != nil {
		errs.errs = append(errs.errs, err)
	}

	return trees.IDs, errs.errs
}
예제 #30
0
파일: cache.go 프로젝트: fawick/restic
// Clear removes information from the cache that isn't present in the repository any more.
func (c *Cache) Clear(repo *repository.Repository) error {
	list, err := c.list(backend.Snapshot)
	if err != nil {
		return err
	}

	for _, entry := range list {
		debug.Log("Cache.Clear", "found entry %v", entry)

		if ok, err := repo.Backend().Test(backend.Snapshot, entry.ID.String()); !ok || err != nil {
			debug.Log("Cache.Clear", "snapshot %v doesn't exist any more, removing %v", entry.ID, entry)

			err = c.purge(backend.Snapshot, entry.Subtype, entry.ID)
			if err != nil {
				return err
			}
		}
	}

	return nil
}