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