k8s.io/kubernetes@v1.29.3/pkg/util/filesystem/defaultfs.go (about) 1 /* 2 Copyright 2017 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package filesystem 18 19 import ( 20 "fmt" 21 "os" 22 "path/filepath" 23 "runtime" 24 "strings" 25 "time" 26 ) 27 28 // DefaultFs implements Filesystem using same-named functions from "os" and "io" 29 type DefaultFs struct { 30 root string 31 } 32 33 var _ Filesystem = &DefaultFs{} 34 35 // NewTempFs returns a fake Filesystem in temporary directory, useful for unit tests 36 func NewTempFs() Filesystem { 37 path, _ := os.MkdirTemp("", "tmpfs") 38 return &DefaultFs{ 39 root: path, 40 } 41 } 42 43 func (fs *DefaultFs) prefix(path string) string { 44 if len(fs.root) == 0 { 45 return path 46 } 47 return filepath.Join(fs.root, path) 48 } 49 50 // Stat via os.Stat 51 func (fs *DefaultFs) Stat(name string) (os.FileInfo, error) { 52 return os.Stat(fs.prefix(name)) 53 } 54 55 // Create via os.Create 56 func (fs *DefaultFs) Create(name string) (File, error) { 57 file, err := os.Create(fs.prefix(name)) 58 if err != nil { 59 return nil, err 60 } 61 return &defaultFile{file}, nil 62 } 63 64 // Rename via os.Rename 65 func (fs *DefaultFs) Rename(oldpath, newpath string) error { 66 if !strings.HasPrefix(oldpath, fs.root) { 67 oldpath = fs.prefix(oldpath) 68 } 69 if !strings.HasPrefix(newpath, fs.root) { 70 newpath = fs.prefix(newpath) 71 } 72 return os.Rename(oldpath, newpath) 73 } 74 75 // MkdirAll via os.MkdirAll 76 func (fs *DefaultFs) MkdirAll(path string, perm os.FileMode) error { 77 return os.MkdirAll(fs.prefix(path), perm) 78 } 79 80 // MkdirAllWithPathCheck checks if path exists already. If not, it creates a directory 81 // named path, along with any necessary parents, and returns nil, or else returns an error. 82 // Permission bits perm (before umask) are used for all directories that 83 // MkdirAllWithPathCheck creates. 84 // If path is already a directory, MkdirAllWithPathCheck does nothing and returns nil. 85 // NOTE: In case of Windows NTFS, mount points are implemented as reparse-point 86 // (similar to symlink) and do not represent actual directory. Hence Directory existence 87 // check for windows NTFS will NOT check for dir, but for symlink presence. 88 func MkdirAllWithPathCheck(path string, perm os.FileMode) error { 89 if dir, err := os.Lstat(path); err == nil { 90 // If the path exists already, 91 // 1. for Unix/Linux OS, check if the path is directory. 92 // 2. for windows NTFS, check if the path is symlink instead of directory. 93 if dir.IsDir() || 94 (runtime.GOOS == "windows" && (dir.Mode()&os.ModeSymlink != 0)) { 95 return nil 96 } 97 return fmt.Errorf("path %v exists but is not a directory", path) 98 } 99 // If existence of path not known, attempt to create it. 100 if err := os.MkdirAll(path, perm); err != nil { 101 return err 102 } 103 return nil 104 } 105 106 // Chtimes via os.Chtimes 107 func (fs *DefaultFs) Chtimes(name string, atime time.Time, mtime time.Time) error { 108 return os.Chtimes(fs.prefix(name), atime, mtime) 109 } 110 111 // RemoveAll via os.RemoveAll 112 func (fs *DefaultFs) RemoveAll(path string) error { 113 return os.RemoveAll(fs.prefix(path)) 114 } 115 116 // Remove via os.Remove 117 func (fs *DefaultFs) Remove(name string) error { 118 return os.Remove(fs.prefix(name)) 119 } 120 121 // ReadFile via os.ReadFile 122 func (fs *DefaultFs) ReadFile(filename string) ([]byte, error) { 123 return os.ReadFile(fs.prefix(filename)) 124 } 125 126 // TempDir via os.MkdirTemp 127 func (fs *DefaultFs) TempDir(dir, prefix string) (string, error) { 128 return os.MkdirTemp(fs.prefix(dir), prefix) 129 } 130 131 // TempFile via os.CreateTemp 132 func (fs *DefaultFs) TempFile(dir, prefix string) (File, error) { 133 file, err := os.CreateTemp(fs.prefix(dir), prefix) 134 if err != nil { 135 return nil, err 136 } 137 return &defaultFile{file}, nil 138 } 139 140 // ReadDir via os.ReadDir 141 func (fs *DefaultFs) ReadDir(dirname string) ([]os.DirEntry, error) { 142 return os.ReadDir(fs.prefix(dirname)) 143 } 144 145 // Walk via filepath.Walk 146 func (fs *DefaultFs) Walk(root string, walkFn filepath.WalkFunc) error { 147 return filepath.Walk(fs.prefix(root), walkFn) 148 } 149 150 // defaultFile implements File using same-named functions from "os" 151 type defaultFile struct { 152 file *os.File 153 } 154 155 // Name via os.File.Name 156 func (file *defaultFile) Name() string { 157 return file.file.Name() 158 } 159 160 // Write via os.File.Write 161 func (file *defaultFile) Write(b []byte) (n int, err error) { 162 return file.file.Write(b) 163 } 164 165 // Sync via os.File.Sync 166 func (file *defaultFile) Sync() error { 167 return file.file.Sync() 168 } 169 170 // Close via os.File.Close 171 func (file *defaultFile) Close() error { 172 return file.file.Close() 173 }