github.com/klaytn/klaytn@v1.10.2/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 "io/ioutil" 25 "os" 26 "path/filepath" 27 "strings" 28 "sync" 29 "time" 30 31 "gopkg.in/fatih/set.v0" 32 ) 33 34 // fileCache is a cache of files seen during scan of keystore. 35 type fileCache struct { 36 all *set.SetNonTS // Set of all files from the keystore folder 37 lastMod time.Time // Last time instance when a file was modified 38 mu sync.RWMutex 39 } 40 41 // scan performs a new scan on the given directory, compares against the already 42 // cached filenames, and returns file sets: creates, deletes, updates. 43 func (fc *fileCache) scan(keyDir string) (set.Interface, set.Interface, set.Interface, error) { 44 t0 := time.Now() 45 46 // List all the failes from the keystore folder 47 files, err := ioutil.ReadDir(keyDir) 48 if err != nil { 49 return nil, nil, nil, err 50 } 51 t1 := time.Now() 52 53 fc.mu.Lock() 54 defer fc.mu.Unlock() 55 56 // Iterate all the files and gather their metadata 57 all := set.NewNonTS() 58 mods := set.NewNonTS() 59 60 var newLastMod time.Time 61 for _, fi := range files { 62 // Skip any non-key files from the folder 63 path := filepath.Join(keyDir, fi.Name()) 64 if skipKeyFile(fi) { 65 logger.Trace("Ignoring file on account scan", "path", path) 66 continue 67 } 68 // Gather the set of all and fresly modified files 69 all.Add(path) 70 71 modified := fi.ModTime() 72 if modified.After(fc.lastMod) { 73 mods.Add(path) 74 } 75 if modified.After(newLastMod) { 76 newLastMod = modified 77 } 78 } 79 t2 := time.Now() 80 81 // Update the tracked files and return the three sets 82 deletes := set.Difference(fc.all, all) // Deletes = previous - current 83 creates := set.Difference(all, fc.all) // Creates = current - previous 84 updates := set.Difference(mods, creates) // Updates = modified - creates 85 86 fc.all, fc.lastMod = all, newLastMod 87 t3 := time.Now() 88 89 // Report on the scanning stats and return 90 logger.Debug("FS scan times", "list", t1.Sub(t0), "set", t2.Sub(t1), "diff", t3.Sub(t2)) 91 return creates, deletes, updates, nil 92 } 93 94 // skipKeyFile ignores editor backups, hidden files and folders/symlinks. 95 func skipKeyFile(fi os.FileInfo) bool { 96 // Skip editor backups and UNIX-style hidden files. 97 if strings.HasSuffix(fi.Name(), "~") || strings.HasPrefix(fi.Name(), ".") { 98 return true 99 } 100 // Skip misc special files, directories (yes, symlinks too). 101 if fi.IsDir() || fi.Mode()&os.ModeType != 0 { 102 return true 103 } 104 return false 105 }