filestore.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. /*
  2. Copyright 2017 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package store
  14. import (
  15. "fmt"
  16. "os"
  17. "path/filepath"
  18. "strings"
  19. utilfs "k8s.io/kubernetes/pkg/util/filesystem"
  20. )
  21. const (
  22. // Name prefix for the temporary files.
  23. tmpPrefix = "."
  24. )
  25. // FileStore is an implementation of the Store interface which stores data in files.
  26. type FileStore struct {
  27. // Absolute path to the base directory for storing data files.
  28. directoryPath string
  29. // filesystem to use.
  30. filesystem utilfs.Filesystem
  31. }
  32. // NewFileStore returns an instance of FileStore.
  33. func NewFileStore(path string, fs utilfs.Filesystem) (Store, error) {
  34. if err := ensureDirectory(fs, path); err != nil {
  35. return nil, err
  36. }
  37. return &FileStore{directoryPath: path, filesystem: fs}, nil
  38. }
  39. // Write writes the given data to a file named key.
  40. func (f *FileStore) Write(key string, data []byte) error {
  41. if err := ValidateKey(key); err != nil {
  42. return err
  43. }
  44. if err := ensureDirectory(f.filesystem, f.directoryPath); err != nil {
  45. return err
  46. }
  47. return writeFile(f.filesystem, f.getPathByKey(key), data)
  48. }
  49. // Read reads the data from the file named key.
  50. func (f *FileStore) Read(key string) ([]byte, error) {
  51. if err := ValidateKey(key); err != nil {
  52. return nil, err
  53. }
  54. bytes, err := f.filesystem.ReadFile(f.getPathByKey(key))
  55. if os.IsNotExist(err) {
  56. return bytes, ErrKeyNotFound
  57. }
  58. return bytes, err
  59. }
  60. // Delete deletes the key file.
  61. func (f *FileStore) Delete(key string) error {
  62. if err := ValidateKey(key); err != nil {
  63. return err
  64. }
  65. return removePath(f.filesystem, f.getPathByKey(key))
  66. }
  67. // List returns all keys in the store.
  68. func (f *FileStore) List() ([]string, error) {
  69. keys := make([]string, 0)
  70. files, err := f.filesystem.ReadDir(f.directoryPath)
  71. if err != nil {
  72. return keys, err
  73. }
  74. for _, f := range files {
  75. if !strings.HasPrefix(f.Name(), tmpPrefix) {
  76. keys = append(keys, f.Name())
  77. }
  78. }
  79. return keys, nil
  80. }
  81. // getPathByKey returns the full path of the file for the key.
  82. func (f *FileStore) getPathByKey(key string) string {
  83. return filepath.Join(f.directoryPath, key)
  84. }
  85. // ensureDirectory creates the directory if it does not exist.
  86. func ensureDirectory(fs utilfs.Filesystem, path string) error {
  87. if _, err := fs.Stat(path); err != nil {
  88. // MkdirAll returns nil if directory already exists.
  89. return fs.MkdirAll(path, 0755)
  90. }
  91. return nil
  92. }
  93. // writeFile writes data to path in a single transaction.
  94. func writeFile(fs utilfs.Filesystem, path string, data []byte) (retErr error) {
  95. // Create a temporary file in the base directory of `path` with a prefix.
  96. tmpFile, err := fs.TempFile(filepath.Dir(path), tmpPrefix)
  97. if err != nil {
  98. return err
  99. }
  100. tmpPath := tmpFile.Name()
  101. shouldClose := true
  102. defer func() {
  103. // Close the file.
  104. if shouldClose {
  105. if err := tmpFile.Close(); err != nil {
  106. if retErr == nil {
  107. retErr = fmt.Errorf("close error: %v", err)
  108. } else {
  109. retErr = fmt.Errorf("failed to close temp file after error %v; close error: %v", retErr, err)
  110. }
  111. }
  112. }
  113. // Clean up the temp file on error.
  114. if retErr != nil && tmpPath != "" {
  115. if err := removePath(fs, tmpPath); err != nil {
  116. retErr = fmt.Errorf("failed to remove the temporary file (%q) after error %v; remove error: %v", tmpPath, retErr, err)
  117. }
  118. }
  119. }()
  120. // Write data.
  121. if _, err := tmpFile.Write(data); err != nil {
  122. return err
  123. }
  124. // Sync file.
  125. if err := tmpFile.Sync(); err != nil {
  126. return err
  127. }
  128. // Closing the file before renaming.
  129. err = tmpFile.Close()
  130. shouldClose = false
  131. if err != nil {
  132. return err
  133. }
  134. return fs.Rename(tmpPath, path)
  135. }
  136. func removePath(fs utilfs.Filesystem, path string) error {
  137. if err := fs.Remove(path); err != nil && !os.IsNotExist(err) {
  138. return err
  139. }
  140. return nil
  141. }