github.com/klaytn/klaytn@v1.12.1/accounts/keystore/file_cache.go (about) 1 // Modifications Copyright 2018 The klaytn Authors 2 // Copyright 2017 The go-ethereum Authors 3 // This file is part of the go-ethereum library. 4 // 5 // The go-ethereum library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-ethereum library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 17 // 18 // This file is derived from accounts/keystore/file_cache.go (2018/06/04). 19 // Modified and improved for the klaytn development. 20 21 package keystore 22 23 import ( 24 "os" 25 "path/filepath" 26 "strings" 27 "sync" 28 "time" 29 30 "gopkg.in/fatih/set.v0" 31 ) 32 33 // fileCache is a cache of files seen during scan of keystore. 34 type fileCache struct { 35 all *set.SetNonTS // Set of all files from the keystore folder 36 lastMod time.Time // Last time instance when a file was modified 37 mu sync.RWMutex 38 } 39 40 // scan performs a new scan on the given directory, compares against the already 41 // cached filenames, and returns file sets: creates, deletes, updates. 42 func (fc *fileCache) scan(keyDir string) (set.Interface, set.Interface, set.Interface, error) { 43 t0 := time.Now() 44 45 // List all the failes from the keystore folder 46 files, err := os.ReadDir(keyDir) 47 if err != nil { 48 return nil, nil, nil, err 49 } 50 t1 := time.Now() 51 52 fc.mu.Lock() 53 defer fc.mu.Unlock() 54 55 // Iterate all the files and gather their metadata 56 all := set.NewNonTS() 57 mods := set.NewNonTS() 58 59 var newLastMod time.Time 60 for _, fi := range files { 61 // Skip any non-key files from the folder 62 path := filepath.Join(keyDir, fi.Name()) 63 if skipKeyFile(fi) { 64 logger.Trace("Ignoring file on account scan", "path", path) 65 continue 66 } 67 // Gather the set of all and fresly modified files 68 all.Add(path) 69 70 finfo, err := fi.Info() 71 if err != nil { 72 return nil, nil, nil, err 73 } 74 modified := finfo.ModTime() 75 if modified.After(fc.lastMod) { 76 mods.Add(path) 77 } 78 if modified.After(newLastMod) { 79 newLastMod = modified 80 } 81 } 82 t2 := time.Now() 83 84 // Update the tracked files and return the three sets 85 deletes := set.Difference(fc.all, all) // Deletes = previous - current 86 creates := set.Difference(all, fc.all) // Creates = current - previous 87 updates := set.Difference(mods, creates) // Updates = modified - creates 88 89 fc.all, fc.lastMod = all, newLastMod 90 t3 := time.Now() 91 92 // Report on the scanning stats and return 93 logger.Debug("FS scan times", "list", t1.Sub(t0), "set", t2.Sub(t1), "diff", t3.Sub(t2)) 94 return creates, deletes, updates, nil 95 } 96 97 // skipKeyFile ignores editor backups, hidden files and folders/symlinks. 98 func skipKeyFile(fi os.DirEntry) bool { 99 // Skip editor backups and UNIX-style hidden files. 100 if strings.HasSuffix(fi.Name(), "~") || strings.HasPrefix(fi.Name(), ".") { 101 return true 102 } 103 // Skip misc special files, directories (yes, symlinks too). 104 if fi.IsDir() || fi.Type()&os.ModeType != 0 { 105 return true 106 } 107 return false 108 }