Skip to content

Commit

Permalink
FileStorage: Fix List(); modify Storage interface (fixes #4)
Browse files Browse the repository at this point in the history
Adding a recursive option to List(), which, if true, causes List to
act like a walk function.

Also differentiating between "terminal" keys and "non-terminal" in
KeyInfo, since sometimes directories are useful, like listing user
accounts.
  • Loading branch information
mholt committed Dec 12, 2018
1 parent 9645f8e commit b2a67f0
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 22 deletions.
46 changes: 33 additions & 13 deletions filestorage.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"fmt"
"io/ioutil"
"os"
"path"
"path/filepath"
"runtime"
"sync"
Expand Down Expand Up @@ -67,16 +68,34 @@ func (fs FileStorage) Delete(key string) error {
}

// List returns all keys that match prefix.
func (fs FileStorage) List(prefix string) ([]string, error) {
d, err := os.Open(fs.Filename(prefix))
if os.IsNotExist(err) {
return nil, ErrNotExist(err)
}
if err != nil {
return nil, err
}
defer d.Close()
return d.Readdirnames(-1)
func (fs FileStorage) List(prefix string, recursive bool) ([]string, error) {
var keys []string
walkPrefix := fs.Filename(prefix)

err := filepath.Walk(walkPrefix, func(fpath string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info == nil {
return fmt.Errorf("%s: file info is nil", fpath)
}
if fpath == walkPrefix {
return nil
}

suffix, err := filepath.Rel(walkPrefix, fpath)
if err != nil {
return fmt.Errorf("%s: could not make path relative: %v", fpath, err)
}
keys = append(keys, path.Join(prefix, suffix))

if !recursive && info.IsDir() {
return filepath.SkipDir
}
return nil
})

return keys, err
}

// Stat returns information about key.
Expand All @@ -89,9 +108,10 @@ func (fs FileStorage) Stat(key string) (KeyInfo, error) {
return KeyInfo{}, err
}
return KeyInfo{
Key: key,
Modified: fi.ModTime(),
Size: fi.Size(),
Key: key,
Modified: fi.ModTime(),
Size: fi.Size(),
IsTerminal: !fi.IsDir(),
}, nil
}

Expand Down
2 changes: 1 addition & 1 deletion maintain.go
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ func (certCache *Cache) updateOCSPStaples() {
// deleteOldStapleFiles deletes cached OCSP staples that have expired.
// TODO: We should do this for long-expired certificates, too.
func (certCache *Cache) deleteOldStapleFiles() {
ocspKeys, err := certCache.storage.List(prefixOCSP)
ocspKeys, err := certCache.storage.List(prefixOCSP, false)
if err != nil {
// maybe just hasn't been created yet; no big deal
return
Expand Down
13 changes: 9 additions & 4 deletions storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,11 @@ type Storage interface {
Exists(key string) bool

// List returns all keys that match prefix.
List(prefix string) ([]string, error)
// If recursive is true, non-terminal keys
// will be enumerated (i.e. "directories"
// should be walked); otherwise, only keys
// prefixed exactly by prefix will be listed.
List(prefix string, recursive bool) ([]string, error)

// Stat returns information about key.
Stat(key string) (KeyInfo, error)
Expand Down Expand Up @@ -92,9 +96,10 @@ type Waiter interface {

// KeyInfo holds information about a key in storage.
type KeyInfo struct {
Key string
Modified time.Time
Size int64
Key string
Modified time.Time
Size int64
IsTerminal bool // false for keys that only contain other keys (like directories)
}

// storeTx stores all the values or none at all.
Expand Down
9 changes: 5 additions & 4 deletions user.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"fmt"
"io"
"os"
"path"
"sort"
"strings"

Expand Down Expand Up @@ -240,16 +241,16 @@ func (cfg *Config) askUserAgreement(agreementURL string) bool {
// account, errors here are discarded to simplify code flow in
// the caller, and errors are not important here anyway.
func (cfg *Config) mostRecentUserEmail() string {
userList, err := cfg.certCache.storage.List(StorageKeys.UsersPrefix(cfg.CA))
userList, err := cfg.certCache.storage.List(StorageKeys.UsersPrefix(cfg.CA), false)
if err != nil || len(userList) == 0 {
return ""
}
sort.Slice(userList, func(i, j int) bool {
iInfo, _ := cfg.certCache.storage.Stat(StorageKeys.UserPrefix(cfg.CA, userList[i]))
jInfo, _ := cfg.certCache.storage.Stat(StorageKeys.UserPrefix(cfg.CA, userList[j]))
iInfo, _ := cfg.certCache.storage.Stat(userList[i])
jInfo, _ := cfg.certCache.storage.Stat(userList[j])
return jInfo.Modified.Before(iInfo.Modified)
})
user, err := cfg.getUser(userList[0])
user, err := cfg.getUser(path.Base(userList[0]))
if err != nil {
return ""
}
Expand Down

0 comments on commit b2a67f0

Please sign in to comment.