123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168 |
- /*
- Copyright 2017 The Kubernetes Authors.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
- package store
- import (
- "fmt"
- "os"
- "path/filepath"
- "strings"
- utilfs "k8s.io/kubernetes/pkg/util/filesystem"
- )
- const (
- // Name prefix for the temporary files.
- tmpPrefix = "."
- )
- // FileStore is an implementation of the Store interface which stores data in files.
- type FileStore struct {
- // Absolute path to the base directory for storing data files.
- directoryPath string
- // filesystem to use.
- filesystem utilfs.Filesystem
- }
- // NewFileStore returns an instance of FileStore.
- func NewFileStore(path string, fs utilfs.Filesystem) (Store, error) {
- if err := ensureDirectory(fs, path); err != nil {
- return nil, err
- }
- return &FileStore{directoryPath: path, filesystem: fs}, nil
- }
- // Write writes the given data to a file named key.
- func (f *FileStore) Write(key string, data []byte) error {
- if err := ValidateKey(key); err != nil {
- return err
- }
- if err := ensureDirectory(f.filesystem, f.directoryPath); err != nil {
- return err
- }
- return writeFile(f.filesystem, f.getPathByKey(key), data)
- }
- // Read reads the data from the file named key.
- func (f *FileStore) Read(key string) ([]byte, error) {
- if err := ValidateKey(key); err != nil {
- return nil, err
- }
- bytes, err := f.filesystem.ReadFile(f.getPathByKey(key))
- if os.IsNotExist(err) {
- return bytes, ErrKeyNotFound
- }
- return bytes, err
- }
- // Delete deletes the key file.
- func (f *FileStore) Delete(key string) error {
- if err := ValidateKey(key); err != nil {
- return err
- }
- return removePath(f.filesystem, f.getPathByKey(key))
- }
- // List returns all keys in the store.
- func (f *FileStore) List() ([]string, error) {
- keys := make([]string, 0)
- files, err := f.filesystem.ReadDir(f.directoryPath)
- if err != nil {
- return keys, err
- }
- for _, f := range files {
- if !strings.HasPrefix(f.Name(), tmpPrefix) {
- keys = append(keys, f.Name())
- }
- }
- return keys, nil
- }
- // getPathByKey returns the full path of the file for the key.
- func (f *FileStore) getPathByKey(key string) string {
- return filepath.Join(f.directoryPath, key)
- }
- // ensureDirectory creates the directory if it does not exist.
- func ensureDirectory(fs utilfs.Filesystem, path string) error {
- if _, err := fs.Stat(path); err != nil {
- // MkdirAll returns nil if directory already exists.
- return fs.MkdirAll(path, 0755)
- }
- return nil
- }
- // writeFile writes data to path in a single transaction.
- func writeFile(fs utilfs.Filesystem, path string, data []byte) (retErr error) {
- // Create a temporary file in the base directory of `path` with a prefix.
- tmpFile, err := fs.TempFile(filepath.Dir(path), tmpPrefix)
- if err != nil {
- return err
- }
- tmpPath := tmpFile.Name()
- shouldClose := true
- defer func() {
- // Close the file.
- if shouldClose {
- if err := tmpFile.Close(); err != nil {
- if retErr == nil {
- retErr = fmt.Errorf("close error: %v", err)
- } else {
- retErr = fmt.Errorf("failed to close temp file after error %v; close error: %v", retErr, err)
- }
- }
- }
- // Clean up the temp file on error.
- if retErr != nil && tmpPath != "" {
- if err := removePath(fs, tmpPath); err != nil {
- retErr = fmt.Errorf("failed to remove the temporary file (%q) after error %v; remove error: %v", tmpPath, retErr, err)
- }
- }
- }()
- // Write data.
- if _, err := tmpFile.Write(data); err != nil {
- return err
- }
- // Sync file.
- if err := tmpFile.Sync(); err != nil {
- return err
- }
- // Closing the file before renaming.
- err = tmpFile.Close()
- shouldClose = false
- if err != nil {
- return err
- }
- return fs.Rename(tmpPath, path)
- }
- func removePath(fs utilfs.Filesystem, path string) error {
- if err := fs.Remove(path); err != nil && !os.IsNotExist(err) {
- return err
- }
- return nil
- }
|