mirror of https://github.com/restic/restic.git
repository: Refactor Config
This commit is contained in:
parent
867f6c8e24
commit
c553a57e0d
|
@ -0,0 +1,87 @@
|
||||||
|
package repository
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/restic/restic/backend"
|
||||||
|
"github.com/restic/restic/chunker"
|
||||||
|
"github.com/restic/restic/debug"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Config contains the configuration for a repository.
|
||||||
|
type Config struct {
|
||||||
|
Version uint `json:"version"`
|
||||||
|
ID string `json:"id"`
|
||||||
|
ChunkerPolynomial chunker.Pol `json:"chunker_polynomial"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// repositoryIDSize is the length of the ID chosen at random for a new repository.
|
||||||
|
const repositoryIDSize = sha256.Size
|
||||||
|
|
||||||
|
// RepoVersion is the version that is written to the config when a repository
|
||||||
|
// is newly created with Init().
|
||||||
|
const RepoVersion = 1
|
||||||
|
|
||||||
|
// JSONUnpackedSaver saves unpacked JSON.
|
||||||
|
type JSONUnpackedSaver interface {
|
||||||
|
SaveJSONUnpacked(backend.Type, interface{}) (backend.ID, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// JSONUnpackedLoader loads unpacked JSON.
|
||||||
|
type JSONUnpackedLoader interface {
|
||||||
|
LoadJSONUnpacked(backend.Type, backend.ID, interface{}) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateConfig creates a config file with a randomly selected polynomial and
|
||||||
|
// ID and saves the config in the repository.
|
||||||
|
func CreateConfig(r JSONUnpackedSaver) (Config, error) {
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
cfg Config
|
||||||
|
)
|
||||||
|
|
||||||
|
cfg.ChunkerPolynomial, err = chunker.RandomPolynomial()
|
||||||
|
if err != nil {
|
||||||
|
return Config{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
newID := make([]byte, repositoryIDSize)
|
||||||
|
_, err = io.ReadFull(rand.Reader, newID)
|
||||||
|
if err != nil {
|
||||||
|
return Config{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg.ID = hex.EncodeToString(newID)
|
||||||
|
cfg.Version = RepoVersion
|
||||||
|
|
||||||
|
debug.Log("Repo.CreateConfig", "New config: %#v", cfg)
|
||||||
|
|
||||||
|
_, err = r.SaveJSONUnpacked(backend.Config, cfg)
|
||||||
|
return cfg, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadConfig returns loads, checks and returns the config for a repository.
|
||||||
|
func LoadConfig(r JSONUnpackedLoader) (Config, error) {
|
||||||
|
var (
|
||||||
|
cfg Config
|
||||||
|
)
|
||||||
|
|
||||||
|
err := r.LoadJSONUnpacked(backend.Config, nil, &cfg)
|
||||||
|
if err != nil {
|
||||||
|
return Config{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.Version != RepoVersion {
|
||||||
|
return Config{}, errors.New("unsupported repository version")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !cfg.ChunkerPolynomial.Irreducible() {
|
||||||
|
return Config{}, errors.New("invalid chunker polynomial")
|
||||||
|
}
|
||||||
|
|
||||||
|
return cfg, nil
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
package repository_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/restic/restic/backend"
|
||||||
|
"github.com/restic/restic/repository"
|
||||||
|
. "github.com/restic/restic/test"
|
||||||
|
)
|
||||||
|
|
||||||
|
type saver func(backend.Type, interface{}) (backend.ID, error)
|
||||||
|
|
||||||
|
func (s saver) SaveJSONUnpacked(t backend.Type, arg interface{}) (backend.ID, error) {
|
||||||
|
return s(t, arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
type loader func(backend.Type, backend.ID, interface{}) error
|
||||||
|
|
||||||
|
func (l loader) LoadJSONUnpacked(t backend.Type, id backend.ID, arg interface{}) error {
|
||||||
|
return l(t, id, arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConfig(t *testing.T) {
|
||||||
|
resultConfig := repository.Config{}
|
||||||
|
save := func(tpe backend.Type, arg interface{}) (backend.ID, error) {
|
||||||
|
Assert(t, tpe == backend.Config,
|
||||||
|
"wrong backend type: got %v, wanted %v",
|
||||||
|
tpe, backend.Config)
|
||||||
|
|
||||||
|
cfg := arg.(repository.Config)
|
||||||
|
resultConfig = cfg
|
||||||
|
return backend.ID{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg1, err := repository.CreateConfig(saver(save))
|
||||||
|
OK(t, err)
|
||||||
|
|
||||||
|
load := func(tpe backend.Type, id backend.ID, arg interface{}) error {
|
||||||
|
Assert(t, tpe == backend.Config,
|
||||||
|
"wrong backend type: got %v, wanted %v",
|
||||||
|
tpe, backend.Config)
|
||||||
|
|
||||||
|
cfg := arg.(*repository.Config)
|
||||||
|
*cfg = resultConfig
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg2, err := repository.LoadConfig(loader(load))
|
||||||
|
OK(t, err)
|
||||||
|
|
||||||
|
Assert(t, cfg1 == cfg2,
|
||||||
|
"configs aren't equal: %v != %v", cfg1, cfg2)
|
||||||
|
}
|
|
@ -2,9 +2,7 @@ package repository
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/rand"
|
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"encoding/hex"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -19,13 +17,6 @@ import (
|
||||||
"github.com/restic/restic/pack"
|
"github.com/restic/restic/pack"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Config contains the configuration for a repository.
|
|
||||||
type Config struct {
|
|
||||||
Version uint `json:"version"`
|
|
||||||
ID string `json:"id"`
|
|
||||||
ChunkerPolynomial chunker.Pol `json:"chunker_polynomial"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Repository is used to access a repository in a backend.
|
// Repository is used to access a repository in a backend.
|
||||||
type Repository struct {
|
type Repository struct {
|
||||||
be backend.Backend
|
be backend.Backend
|
||||||
|
@ -526,47 +517,6 @@ func (r *Repository) loadIndex(id string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
const repositoryIDSize = sha256.Size
|
|
||||||
const RepoVersion = 1
|
|
||||||
|
|
||||||
func createConfig(r *Repository) (err error) {
|
|
||||||
r.Config.ChunkerPolynomial, err = chunker.RandomPolynomial()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
newID := make([]byte, repositoryIDSize)
|
|
||||||
_, err = io.ReadFull(rand.Reader, newID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
r.Config.ID = hex.EncodeToString(newID)
|
|
||||||
r.Config.Version = RepoVersion
|
|
||||||
|
|
||||||
debug.Log("Repo.createConfig", "New config: %#v", r.Config)
|
|
||||||
|
|
||||||
_, err = r.SaveJSONUnpacked(backend.Config, r.Config)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Repository) loadConfig(cfg *Config) error {
|
|
||||||
err := r.LoadJSONUnpacked(backend.Config, nil, cfg)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if cfg.Version != RepoVersion {
|
|
||||||
return errors.New("unsupported repository version")
|
|
||||||
}
|
|
||||||
|
|
||||||
if !cfg.ChunkerPolynomial.Irreducible() {
|
|
||||||
return errors.New("invalid chunker polynomial")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SearchKey finds a key with the supplied password, afterwards the config is
|
// SearchKey finds a key with the supplied password, afterwards the config is
|
||||||
// read and parsed.
|
// read and parsed.
|
||||||
func (r *Repository) SearchKey(password string) error {
|
func (r *Repository) SearchKey(password string) error {
|
||||||
|
@ -577,11 +527,12 @@ func (r *Repository) SearchKey(password string) error {
|
||||||
|
|
||||||
r.key = key.master
|
r.key = key.master
|
||||||
r.keyName = key.Name()
|
r.keyName = key.Name()
|
||||||
return r.loadConfig(&r.Config)
|
r.Config, err = LoadConfig(r)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init creates a new master key with the supplied password and initializes the
|
// Init creates a new master key with the supplied password, initializes and
|
||||||
// repository config.
|
// saves the repository config.
|
||||||
func (r *Repository) Init(password string) error {
|
func (r *Repository) Init(password string) error {
|
||||||
has, err := r.be.Test(backend.Config, "")
|
has, err := r.be.Test(backend.Config, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -598,7 +549,8 @@ func (r *Repository) Init(password string) error {
|
||||||
|
|
||||||
r.key = key.master
|
r.key = key.master
|
||||||
r.keyName = key.Name()
|
r.keyName = key.Name()
|
||||||
return createConfig(r)
|
r.Config, err = CreateConfig(r)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Repository) Decrypt(ciphertext []byte) ([]byte, error) {
|
func (r *Repository) Decrypt(ciphertext []byte) ([]byte, error) {
|
||||||
|
|
Loading…
Reference in New Issue