...

Source file src/github.com/theupdateframework/go-tuf/local_store.go

Documentation: github.com/theupdateframework/go-tuf

     1  package tuf
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"errors"
     7  	"fmt"
     8  	"io"
     9  	"io/fs"
    10  	"log"
    11  	"os"
    12  	"path/filepath"
    13  	"strings"
    14  
    15  	"github.com/secure-systems-lab/go-securesystemslib/encrypted"
    16  	"github.com/theupdateframework/go-tuf/data"
    17  	"github.com/theupdateframework/go-tuf/internal/fsutil"
    18  	"github.com/theupdateframework/go-tuf/internal/sets"
    19  	"github.com/theupdateframework/go-tuf/pkg/keys"
    20  	"github.com/theupdateframework/go-tuf/util"
    21  )
    22  
    23  type LocalStore interface {
    24  	// GetMeta returns a map from metadata file names (e.g. root.json) to their raw JSON payload or an error.
    25  	GetMeta() (map[string]json.RawMessage, error)
    26  
    27  	// SetMeta is used to update a metadata file name with a JSON payload.
    28  	SetMeta(name string, meta json.RawMessage) error
    29  
    30  	// WalkStagedTargets calls targetsFn for each staged target file in paths.
    31  	// If paths is empty, all staged target files will be walked.
    32  	WalkStagedTargets(paths []string, targetsFn TargetsWalkFunc) error
    33  
    34  	// FileIsStaged determines if a metadata file is currently staged, to avoid incrementing
    35  	// version numbers repeatedly while staged.
    36  	FileIsStaged(filename string) bool
    37  
    38  	// Commit is used to publish staged files to the repository
    39  	//
    40  	// This will also reset the staged meta to signal incrementing version numbers.
    41  	// TUF 1.0 requires that the root metadata version numbers in the repository does not
    42  	// gaps. To avoid this, we will only increment the number once until we commit.
    43  	Commit(bool, map[string]int64, map[string]data.Hashes) error
    44  
    45  	// GetSigners return a list of signers for a role.
    46  	// This may include revoked keys, so the signers should not
    47  	// be used without filtering.
    48  	GetSigners(role string) ([]keys.Signer, error)
    49  
    50  	// SaveSigner adds a signer to a role.
    51  	SaveSigner(role string, signer keys.Signer) error
    52  
    53  	// SignersForRole return a list of signing keys for a role.
    54  	SignersForKeyIDs(keyIDs []string) []keys.Signer
    55  
    56  	// Clean is used to remove all staged manifests.
    57  	Clean() error
    58  }
    59  
    60  type PassphraseChanger interface {
    61  	// ChangePassphrase changes the passphrase for a role keys file.
    62  	ChangePassphrase(string) error
    63  }
    64  
    65  func MemoryStore(meta map[string]json.RawMessage, files map[string][]byte) LocalStore {
    66  	if meta == nil {
    67  		meta = make(map[string]json.RawMessage)
    68  	}
    69  	return &memoryStore{
    70  		meta:           meta,
    71  		stagedMeta:     make(map[string]json.RawMessage),
    72  		files:          files,
    73  		signerForKeyID: make(map[string]keys.Signer),
    74  		keyIDsForRole:  make(map[string][]string),
    75  	}
    76  }
    77  
    78  type memoryStore struct {
    79  	meta       map[string]json.RawMessage
    80  	stagedMeta map[string]json.RawMessage
    81  	files      map[string][]byte
    82  
    83  	signerForKeyID map[string]keys.Signer
    84  	keyIDsForRole  map[string][]string
    85  }
    86  
    87  func (m *memoryStore) GetMeta() (map[string]json.RawMessage, error) {
    88  	meta := make(map[string]json.RawMessage, len(m.meta)+len(m.stagedMeta))
    89  	for key, value := range m.meta {
    90  		meta[key] = value
    91  	}
    92  	for key, value := range m.stagedMeta {
    93  		meta[key] = value
    94  	}
    95  	return meta, nil
    96  }
    97  
    98  func (m *memoryStore) SetMeta(name string, meta json.RawMessage) error {
    99  	m.stagedMeta[name] = meta
   100  	return nil
   101  }
   102  
   103  func (m *memoryStore) FileIsStaged(name string) bool {
   104  	_, ok := m.stagedMeta[name]
   105  	return ok
   106  }
   107  
   108  func (m *memoryStore) WalkStagedTargets(paths []string, targetsFn TargetsWalkFunc) error {
   109  	if len(paths) == 0 {
   110  		for path, data := range m.files {
   111  			if err := targetsFn(path, bytes.NewReader(data)); err != nil {
   112  				return err
   113  			}
   114  		}
   115  		return nil
   116  	}
   117  
   118  	for _, path := range paths {
   119  		data, ok := m.files[path]
   120  		if !ok {
   121  			return ErrFileNotFound{path}
   122  		}
   123  		if err := targetsFn(path, bytes.NewReader(data)); err != nil {
   124  			return err
   125  		}
   126  	}
   127  	return nil
   128  }
   129  
   130  func (m *memoryStore) Commit(consistentSnapshot bool, versions map[string]int64, hashes map[string]data.Hashes) error {
   131  	for name, meta := range m.stagedMeta {
   132  		paths := computeMetadataPaths(consistentSnapshot, name, versions)
   133  		for _, path := range paths {
   134  			m.meta[path] = meta
   135  		}
   136  		// Remove from staged metadata.
   137  		// This will prompt incrementing version numbers again now that we've
   138  		// successfully committed the metadata to the local store.
   139  		delete(m.stagedMeta, name)
   140  	}
   141  	return nil
   142  }
   143  
   144  func (m *memoryStore) GetSigners(role string) ([]keys.Signer, error) {
   145  	keyIDs, ok := m.keyIDsForRole[role]
   146  	if ok {
   147  		return m.SignersForKeyIDs(keyIDs), nil
   148  	}
   149  
   150  	return nil, nil
   151  }
   152  
   153  func (m *memoryStore) SaveSigner(role string, signer keys.Signer) error {
   154  	keyIDs := signer.PublicData().IDs()
   155  
   156  	for _, keyID := range keyIDs {
   157  		m.signerForKeyID[keyID] = signer
   158  	}
   159  
   160  	mergedKeyIDs := sets.DeduplicateStrings(append(m.keyIDsForRole[role], keyIDs...))
   161  	m.keyIDsForRole[role] = mergedKeyIDs
   162  	return nil
   163  }
   164  
   165  func (m *memoryStore) SignersForKeyIDs(keyIDs []string) []keys.Signer {
   166  	signers := []keys.Signer{}
   167  	keyIDsSeen := map[string]struct{}{}
   168  
   169  	for _, keyID := range keyIDs {
   170  		signer, ok := m.signerForKeyID[keyID]
   171  		if !ok {
   172  			continue
   173  		}
   174  		addSigner := false
   175  
   176  		for _, skid := range signer.PublicData().IDs() {
   177  			if _, seen := keyIDsSeen[skid]; !seen {
   178  				addSigner = true
   179  			}
   180  
   181  			keyIDsSeen[skid] = struct{}{}
   182  		}
   183  
   184  		if addSigner {
   185  			signers = append(signers, signer)
   186  		}
   187  	}
   188  
   189  	return signers
   190  }
   191  
   192  func (m *memoryStore) Clean() error {
   193  	return nil
   194  }
   195  
   196  type persistedKeys struct {
   197  	Encrypted bool            `json:"encrypted"`
   198  	Data      json.RawMessage `json:"data"`
   199  }
   200  
   201  type StoreOpts struct {
   202  	Logger   *log.Logger
   203  	PassFunc util.PassphraseFunc
   204  }
   205  
   206  func FileSystemStore(dir string, p util.PassphraseFunc) LocalStore {
   207  	return &fileSystemStore{
   208  		dir:            dir,
   209  		passphraseFunc: p,
   210  		logger:         log.New(io.Discard, "", 0),
   211  		signerForKeyID: make(map[string]keys.Signer),
   212  		keyIDsForRole:  make(map[string][]string),
   213  	}
   214  }
   215  
   216  func FileSystemStoreWithOpts(dir string, opts ...StoreOpts) LocalStore {
   217  	store := &fileSystemStore{
   218  		dir:            dir,
   219  		passphraseFunc: nil,
   220  		logger:         log.New(io.Discard, "", 0),
   221  		signerForKeyID: make(map[string]keys.Signer),
   222  		keyIDsForRole:  make(map[string][]string),
   223  	}
   224  	for _, opt := range opts {
   225  		if opt.Logger != nil {
   226  			store.logger = opt.Logger
   227  		}
   228  		if opt.PassFunc != nil {
   229  			store.passphraseFunc = opt.PassFunc
   230  		}
   231  	}
   232  	return store
   233  }
   234  
   235  type fileSystemStore struct {
   236  	dir            string
   237  	passphraseFunc util.PassphraseFunc
   238  	logger         *log.Logger
   239  
   240  	signerForKeyID map[string]keys.Signer
   241  	keyIDsForRole  map[string][]string
   242  }
   243  
   244  func (f *fileSystemStore) repoDir() string {
   245  	return filepath.Join(f.dir, "repository")
   246  }
   247  
   248  func (f *fileSystemStore) stagedDir() string {
   249  	return filepath.Join(f.dir, "staged")
   250  }
   251  
   252  func (f *fileSystemStore) GetMeta() (map[string]json.RawMessage, error) {
   253  	// Build a map of metadata names (e.g. root.json) to their full paths
   254  	// (whether in the committed repo dir, or in the staged repo dir).
   255  	metaPaths := map[string]string{}
   256  
   257  	rd := f.repoDir()
   258  	committed, err := os.ReadDir(f.repoDir())
   259  	if err != nil && !errors.Is(err, fs.ErrNotExist) {
   260  		return nil, fmt.Errorf("could not list repo dir: %w", err)
   261  	}
   262  
   263  	for _, e := range committed {
   264  		imf, err := fsutil.IsMetaFile(e)
   265  		if err != nil {
   266  			return nil, err
   267  		}
   268  		if imf {
   269  			name := e.Name()
   270  			metaPaths[name] = filepath.Join(rd, name)
   271  		}
   272  	}
   273  
   274  	sd := f.stagedDir()
   275  	staged, err := os.ReadDir(sd)
   276  	if err != nil && !errors.Is(err, fs.ErrNotExist) {
   277  		return nil, fmt.Errorf("could not list staged dir: %w", err)
   278  	}
   279  
   280  	for _, e := range staged {
   281  		imf, err := fsutil.IsMetaFile(e)
   282  		if err != nil {
   283  			return nil, err
   284  		}
   285  		if imf {
   286  			name := e.Name()
   287  			metaPaths[name] = filepath.Join(sd, name)
   288  		}
   289  	}
   290  
   291  	meta := make(map[string]json.RawMessage)
   292  	for name, path := range metaPaths {
   293  		f, err := os.ReadFile(path)
   294  		if err != nil {
   295  			return nil, err
   296  		}
   297  		meta[name] = f
   298  	}
   299  	return meta, nil
   300  }
   301  
   302  func (f *fileSystemStore) SetMeta(name string, meta json.RawMessage) error {
   303  	if err := f.createDirs(); err != nil {
   304  		return err
   305  	}
   306  	if err := util.AtomicallyWriteFile(filepath.Join(f.stagedDir(), name), meta, 0644); err != nil {
   307  		return err
   308  	}
   309  	return nil
   310  }
   311  
   312  func (f *fileSystemStore) FileIsStaged(name string) bool {
   313  	_, err := os.Stat(filepath.Join(f.stagedDir(), name))
   314  	return err == nil
   315  }
   316  
   317  func (f *fileSystemStore) createDirs() error {
   318  	for _, dir := range []string{"keys", "repository", "staged/targets"} {
   319  		if err := os.MkdirAll(filepath.Join(f.dir, dir), 0755); err != nil {
   320  			return err
   321  		}
   322  	}
   323  	return nil
   324  }
   325  
   326  func (f *fileSystemStore) WalkStagedTargets(paths []string, targetsFn TargetsWalkFunc) error {
   327  	if len(paths) == 0 {
   328  		walkFunc := func(fpath string, info os.FileInfo, err error) error {
   329  			if err != nil {
   330  				return err
   331  			}
   332  			if info.IsDir() || !info.Mode().IsRegular() {
   333  				return nil
   334  			}
   335  			rel, err := filepath.Rel(filepath.Join(f.stagedDir(), "targets"), fpath)
   336  			if err != nil {
   337  				return err
   338  			}
   339  			file, err := os.Open(fpath)
   340  			if err != nil {
   341  				return err
   342  			}
   343  			defer file.Close()
   344  			return targetsFn(filepath.ToSlash(rel), file)
   345  		}
   346  		return filepath.Walk(filepath.Join(f.stagedDir(), "targets"), walkFunc)
   347  	}
   348  
   349  	// check all the files exist before processing any files
   350  	for _, path := range paths {
   351  		realFilepath := filepath.Join(f.stagedDir(), "targets", path)
   352  		if _, err := os.Stat(realFilepath); err != nil {
   353  			if os.IsNotExist(err) {
   354  				return ErrFileNotFound{realFilepath}
   355  			}
   356  			return err
   357  		}
   358  	}
   359  
   360  	for _, path := range paths {
   361  		realFilepath := filepath.Join(f.stagedDir(), "targets", path)
   362  		file, err := os.Open(realFilepath)
   363  		if err != nil {
   364  			if os.IsNotExist(err) {
   365  				return ErrFileNotFound{realFilepath}
   366  			}
   367  			return err
   368  		}
   369  		err = targetsFn(path, file)
   370  		file.Close()
   371  		if err != nil {
   372  			return err
   373  		}
   374  	}
   375  	return nil
   376  }
   377  
   378  func (f *fileSystemStore) createRepoFile(path string) (*os.File, error) {
   379  	dst := filepath.Join(f.repoDir(), path)
   380  	if err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil {
   381  		return nil, err
   382  	}
   383  	return os.Create(dst)
   384  }
   385  
   386  func (f *fileSystemStore) Commit(consistentSnapshot bool, versions map[string]int64, hashes map[string]data.Hashes) error {
   387  	isTarget := func(path string) bool {
   388  		return strings.HasPrefix(path, "targets/")
   389  	}
   390  	copyToRepo := func(fpath string, info os.FileInfo, err error) error {
   391  		if err != nil {
   392  			return err
   393  		}
   394  		if info.IsDir() || !info.Mode().IsRegular() {
   395  			return nil
   396  		}
   397  		rel, err := filepath.Rel(f.stagedDir(), fpath)
   398  		if err != nil {
   399  			return err
   400  		}
   401  		relpath := filepath.ToSlash(rel)
   402  
   403  		var paths []string
   404  		if isTarget(relpath) {
   405  			paths = computeTargetPaths(consistentSnapshot, relpath, hashes)
   406  		} else {
   407  			paths = computeMetadataPaths(consistentSnapshot, relpath, versions)
   408  		}
   409  		var files []io.Writer
   410  		for _, path := range paths {
   411  			file, err := f.createRepoFile(path)
   412  			if err != nil {
   413  				return err
   414  			}
   415  			defer file.Close()
   416  			files = append(files, file)
   417  		}
   418  		staged, err := os.Open(fpath)
   419  		if err != nil {
   420  			return err
   421  		}
   422  		defer staged.Close()
   423  		if _, err = io.Copy(io.MultiWriter(files...), staged); err != nil {
   424  			return err
   425  		}
   426  		return nil
   427  	}
   428  	// Checks if target file should be deleted
   429  	needsRemoval := func(fpath string) bool {
   430  		if consistentSnapshot {
   431  			// strip out the hash
   432  			name := strings.SplitN(filepath.Base(fpath), ".", 2)
   433  			if len(name) != 2 || name[1] == "" {
   434  				return false
   435  			}
   436  			fpath = filepath.Join(filepath.Dir(fpath), name[1])
   437  		}
   438  		_, ok := hashes[filepath.ToSlash(fpath)]
   439  		return !ok
   440  	}
   441  	// Checks if folder is empty
   442  	folderNeedsRemoval := func(fpath string) bool {
   443  		f, err := os.Open(fpath)
   444  		if err != nil {
   445  			return false
   446  		}
   447  		defer f.Close()
   448  		_, err = f.Readdirnames(1)
   449  		return err == io.EOF
   450  	}
   451  	removeFile := func(fpath string, info os.FileInfo, err error) error {
   452  		if err != nil {
   453  			return err
   454  		}
   455  		rel, err := filepath.Rel(f.repoDir(), fpath)
   456  		if err != nil {
   457  			return err
   458  		}
   459  		relpath := filepath.ToSlash(rel)
   460  		if !info.IsDir() && isTarget(relpath) && needsRemoval(rel) {
   461  			// Delete the target file
   462  			if err := os.Remove(fpath); err != nil {
   463  				return err
   464  			}
   465  			// Delete the target folder too if it's empty
   466  			targetFolder := filepath.Dir(fpath)
   467  			if folderNeedsRemoval(targetFolder) {
   468  				if err := os.Remove(targetFolder); err != nil {
   469  					return err
   470  				}
   471  			}
   472  		}
   473  		return nil
   474  	}
   475  	if err := filepath.Walk(f.stagedDir(), copyToRepo); err != nil {
   476  		return err
   477  	}
   478  	if err := filepath.Walk(f.repoDir(), removeFile); err != nil {
   479  		return err
   480  	}
   481  	return f.Clean()
   482  }
   483  
   484  func (f *fileSystemStore) GetSigners(role string) ([]keys.Signer, error) {
   485  	keyIDs, ok := f.keyIDsForRole[role]
   486  	if ok {
   487  		return f.SignersForKeyIDs(keyIDs), nil
   488  	}
   489  
   490  	privKeys, _, err := f.loadPrivateKeys(role)
   491  	if err != nil {
   492  		if os.IsNotExist(err) {
   493  			return nil, nil
   494  		}
   495  		return nil, err
   496  	}
   497  
   498  	signers := []keys.Signer{}
   499  	for _, key := range privKeys {
   500  		signer, err := keys.GetSigner(key)
   501  		if err != nil {
   502  			return nil, err
   503  		}
   504  
   505  		// Cache the signers.
   506  		for _, keyID := range signer.PublicData().IDs() {
   507  			f.keyIDsForRole[role] = append(f.keyIDsForRole[role], keyID)
   508  			f.signerForKeyID[keyID] = signer
   509  		}
   510  		signers = append(signers, signer)
   511  	}
   512  
   513  	return signers, nil
   514  }
   515  
   516  func (f *fileSystemStore) SignersForKeyIDs(keyIDs []string) []keys.Signer {
   517  	signers := []keys.Signer{}
   518  	keyIDsSeen := map[string]struct{}{}
   519  
   520  	for _, keyID := range keyIDs {
   521  		signer, ok := f.signerForKeyID[keyID]
   522  		if !ok {
   523  			continue
   524  		}
   525  
   526  		addSigner := false
   527  
   528  		for _, skid := range signer.PublicData().IDs() {
   529  			if _, seen := keyIDsSeen[skid]; !seen {
   530  				addSigner = true
   531  			}
   532  
   533  			keyIDsSeen[skid] = struct{}{}
   534  		}
   535  
   536  		if addSigner {
   537  			signers = append(signers, signer)
   538  		}
   539  	}
   540  
   541  	return signers
   542  }
   543  
   544  // ChangePassphrase changes the passphrase for a role keys file. Implements
   545  // PassphraseChanger interface.
   546  func (f *fileSystemStore) ChangePassphrase(role string) error {
   547  	// No need to proceed if passphrase func is not set
   548  	if f.passphraseFunc == nil {
   549  		return ErrPassphraseRequired{role}
   550  	}
   551  	// Read the existing keys (if any)
   552  	// If encrypted, will prompt for existing passphrase
   553  	keys, _, err := f.loadPrivateKeys(role)
   554  	if err != nil {
   555  		if os.IsNotExist(err) {
   556  			f.logger.Printf("Failed to change passphrase. Missing keys file for %s role. \n", role)
   557  		}
   558  		return err
   559  	}
   560  	// Prompt for new passphrase
   561  	pass, err := f.passphraseFunc(role, true, true)
   562  	if err != nil {
   563  		return err
   564  	}
   565  	// Proceed saving the keys
   566  	pk := &persistedKeys{Encrypted: true}
   567  	pk.Data, err = encrypted.Marshal(keys, pass)
   568  	if err != nil {
   569  		return err
   570  	}
   571  	data, err := json.MarshalIndent(pk, "", "\t")
   572  	if err != nil {
   573  		return err
   574  	}
   575  	if err := util.AtomicallyWriteFile(f.keysPath(role), append(data, '\n'), 0600); err != nil {
   576  		return err
   577  	}
   578  	f.logger.Printf("Successfully changed passphrase for %s keys file\n", role)
   579  	return nil
   580  }
   581  
   582  func (f *fileSystemStore) SaveSigner(role string, signer keys.Signer) error {
   583  	if err := f.createDirs(); err != nil {
   584  		return err
   585  	}
   586  
   587  	// add the key to the existing keys (if any)
   588  	privKeys, pass, err := f.loadPrivateKeys(role)
   589  	if err != nil && !os.IsNotExist(err) {
   590  		return err
   591  	}
   592  	key, err := signer.MarshalPrivateKey()
   593  	if err != nil {
   594  		return err
   595  	}
   596  	privKeys = append(privKeys, key)
   597  
   598  	// if loadPrivateKeys didn't return a passphrase (because no keys yet exist)
   599  	// and passphraseFunc is set, get the passphrase so the keys file can
   600  	// be encrypted later (passphraseFunc being nil indicates the keys file
   601  	// should not be encrypted)
   602  	if pass == nil && f.passphraseFunc != nil {
   603  		pass, err = f.passphraseFunc(role, true, false)
   604  		if err != nil {
   605  			return err
   606  		}
   607  	}
   608  
   609  	pk := &persistedKeys{}
   610  	if pass != nil {
   611  		pk.Data, err = encrypted.Marshal(privKeys, pass)
   612  		if err != nil {
   613  			return err
   614  		}
   615  		pk.Encrypted = true
   616  	} else {
   617  		pk.Data, err = json.MarshalIndent(privKeys, "", "\t")
   618  		if err != nil {
   619  			return err
   620  		}
   621  	}
   622  	data, err := json.MarshalIndent(pk, "", "\t")
   623  	if err != nil {
   624  		return err
   625  	}
   626  	if err := util.AtomicallyWriteFile(f.keysPath(role), append(data, '\n'), 0600); err != nil {
   627  		return err
   628  	}
   629  
   630  	// Merge privKeys into f.keyIDsForRole and register signers with
   631  	// f.signerForKeyID.
   632  	keyIDsForRole := f.keyIDsForRole[role]
   633  	for _, key := range privKeys {
   634  		signer, err := keys.GetSigner(key)
   635  		if err != nil {
   636  			return err
   637  		}
   638  
   639  		keyIDs := signer.PublicData().IDs()
   640  
   641  		for _, keyID := range keyIDs {
   642  			f.signerForKeyID[keyID] = signer
   643  		}
   644  
   645  		keyIDsForRole = append(keyIDsForRole, keyIDs...)
   646  	}
   647  
   648  	f.keyIDsForRole[role] = sets.DeduplicateStrings(keyIDsForRole)
   649  
   650  	return nil
   651  }
   652  
   653  // loadPrivateKeys loads keys for the given role and returns them along with the
   654  // passphrase (if read) so that callers don't need to re-read it.
   655  func (f *fileSystemStore) loadPrivateKeys(role string) ([]*data.PrivateKey, []byte, error) {
   656  	file, err := os.Open(f.keysPath(role))
   657  	if err != nil {
   658  		return nil, nil, err
   659  	}
   660  	defer file.Close()
   661  
   662  	pk := &persistedKeys{}
   663  	if err := json.NewDecoder(file).Decode(pk); err != nil {
   664  		return nil, nil, err
   665  	}
   666  
   667  	var keys []*data.PrivateKey
   668  	if !pk.Encrypted {
   669  		if err := json.Unmarshal(pk.Data, &keys); err != nil {
   670  			return nil, nil, err
   671  		}
   672  		return keys, nil, nil
   673  	}
   674  
   675  	// the keys are encrypted so cannot be loaded if passphraseFunc is not set
   676  	if f.passphraseFunc == nil {
   677  		return nil, nil, ErrPassphraseRequired{role}
   678  	}
   679  
   680  	// try the empty string as the password first
   681  	pass := []byte("")
   682  	if err := encrypted.Unmarshal(pk.Data, &keys, pass); err != nil {
   683  		pass, err = f.passphraseFunc(role, false, false)
   684  		if err != nil {
   685  			return nil, nil, err
   686  		}
   687  		if err = encrypted.Unmarshal(pk.Data, &keys, pass); err != nil {
   688  			return nil, nil, err
   689  		}
   690  	}
   691  	return keys, pass, nil
   692  }
   693  
   694  func (f *fileSystemStore) keysPath(role string) string {
   695  	return filepath.Join(f.dir, "keys", role+".json")
   696  }
   697  
   698  func (f *fileSystemStore) Clean() error {
   699  	_, err := os.Stat(filepath.Join(f.repoDir(), "root.json"))
   700  	if os.IsNotExist(err) {
   701  		return ErrNewRepository
   702  	} else if err != nil {
   703  		return err
   704  	}
   705  	if err := os.RemoveAll(f.stagedDir()); err != nil {
   706  		return err
   707  	}
   708  	return os.MkdirAll(filepath.Join(f.stagedDir(), "targets"), 0755)
   709  }
   710  
   711  func computeTargetPaths(consistentSnapshot bool, name string, hashes map[string]data.Hashes) []string {
   712  	if consistentSnapshot {
   713  		return util.HashedPaths(name, hashes[name])
   714  	} else {
   715  		return []string{name}
   716  	}
   717  }
   718  
   719  func computeMetadataPaths(consistentSnapshot bool, name string, versions map[string]int64) []string {
   720  	copyVersion := false
   721  
   722  	switch name {
   723  	case "root.json":
   724  		copyVersion = true
   725  	case "timestamp.json":
   726  		copyVersion = false
   727  	default:
   728  		if consistentSnapshot {
   729  			copyVersion = true
   730  		} else {
   731  			copyVersion = false
   732  		}
   733  	}
   734  
   735  	paths := []string{name}
   736  	if copyVersion {
   737  		paths = append(paths, util.VersionedPath(name, versions[name]))
   738  	}
   739  
   740  	return paths
   741  }
   742  

View as plain text