mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-11-04 04:28:08 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			141 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			141 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package physical
 | 
						|
 | 
						|
import (
 | 
						|
	"encoding/json"
 | 
						|
	"fmt"
 | 
						|
	"os"
 | 
						|
	"path/filepath"
 | 
						|
	"sync"
 | 
						|
)
 | 
						|
 | 
						|
// FileBackend is a physical backend that stores data on disk
 | 
						|
// at a given file path. It can be used for durable single server
 | 
						|
// situations, or to develop locally where durability is not critical.
 | 
						|
//
 | 
						|
// WARNING: the file backend implementation is currently extremely unsafe
 | 
						|
// and non-performant. It is meant mostly for local testing and development.
 | 
						|
// It can be improved in the future.
 | 
						|
type FileBackend struct {
 | 
						|
	Path string
 | 
						|
 | 
						|
	l sync.Mutex
 | 
						|
}
 | 
						|
 | 
						|
// newFileBackend constructs a Filebackend using the given directory
 | 
						|
func newFileBackend(conf map[string]string) (Backend, error) {
 | 
						|
	path, ok := conf["path"]
 | 
						|
	if !ok {
 | 
						|
		return nil, fmt.Errorf("'path' must be set")
 | 
						|
	}
 | 
						|
 | 
						|
	return &FileBackend{Path: path}, nil
 | 
						|
}
 | 
						|
 | 
						|
func (b *FileBackend) Delete(k string) error {
 | 
						|
	b.l.Lock()
 | 
						|
	defer b.l.Unlock()
 | 
						|
 | 
						|
	path, key := b.path(k)
 | 
						|
	path = filepath.Join(path, key)
 | 
						|
 | 
						|
	err := os.Remove(path)
 | 
						|
	if err != nil && os.IsNotExist(err) {
 | 
						|
		err = nil
 | 
						|
	}
 | 
						|
 | 
						|
	return err
 | 
						|
}
 | 
						|
 | 
						|
func (b *FileBackend) Get(k string) (*Entry, error) {
 | 
						|
	b.l.Lock()
 | 
						|
	defer b.l.Unlock()
 | 
						|
 | 
						|
	path, key := b.path(k)
 | 
						|
	path = filepath.Join(path, key)
 | 
						|
 | 
						|
	f, err := os.Open(path)
 | 
						|
	if err != nil {
 | 
						|
		if os.IsNotExist(err) {
 | 
						|
			return nil, nil
 | 
						|
		}
 | 
						|
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	defer f.Close()
 | 
						|
 | 
						|
	var entry Entry
 | 
						|
	dec := json.NewDecoder(f)
 | 
						|
	if err := dec.Decode(&entry); err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	return &entry, nil
 | 
						|
}
 | 
						|
 | 
						|
func (b *FileBackend) Put(entry *Entry) error {
 | 
						|
	path, key := b.path(entry.Key)
 | 
						|
 | 
						|
	b.l.Lock()
 | 
						|
	defer b.l.Unlock()
 | 
						|
 | 
						|
	// Make the parent tree
 | 
						|
	if err := os.MkdirAll(path, 0755); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	// JSON encode the entry and write it
 | 
						|
	f, err := os.OpenFile(
 | 
						|
		filepath.Join(path, key),
 | 
						|
		os.O_CREATE|os.O_TRUNC|os.O_WRONLY,
 | 
						|
		0600)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	defer f.Close()
 | 
						|
	enc := json.NewEncoder(f)
 | 
						|
	return enc.Encode(entry)
 | 
						|
}
 | 
						|
 | 
						|
func (b *FileBackend) List(prefix string) ([]string, error) {
 | 
						|
	b.l.Lock()
 | 
						|
	defer b.l.Unlock()
 | 
						|
 | 
						|
	path := b.Path
 | 
						|
	if prefix != "" {
 | 
						|
		path = filepath.Join(path, prefix)
 | 
						|
	}
 | 
						|
 | 
						|
	// Read the directory contents
 | 
						|
	f, err := os.Open(path)
 | 
						|
	if err != nil {
 | 
						|
		if os.IsNotExist(err) {
 | 
						|
			return nil, nil
 | 
						|
		}
 | 
						|
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	defer f.Close()
 | 
						|
 | 
						|
	names, err := f.Readdirnames(-1)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	for i, name := range names {
 | 
						|
		if name[0] == '_' {
 | 
						|
			names[i] = name[1:]
 | 
						|
		} else {
 | 
						|
			names[i] = name + "/"
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return names, nil
 | 
						|
}
 | 
						|
 | 
						|
func (b *FileBackend) path(k string) (string, string) {
 | 
						|
	path := filepath.Join(b.Path, k)
 | 
						|
	key := filepath.Base(path)
 | 
						|
	path = filepath.Dir(path)
 | 
						|
	return path, "_" + key
 | 
						|
}
 |