103 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
		
		
			
		
	
	
			103 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
|   | // Copyright 2017 The go-ethereum Authors | ||
|  | // This file is part of the go-ethereum library. | ||
|  | // | ||
|  | // The go-ethereum library is free software: you can redistribute it and/or modify | ||
|  | // it under the terms of the GNU Lesser General Public License as published by | ||
|  | // the Free Software Foundation, either version 3 of the License, or | ||
|  | // (at your option) any later version. | ||
|  | // | ||
|  | // The go-ethereum library is distributed in the hope that it will be useful, | ||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
|  | // GNU Lesser General Public License for more details. | ||
|  | // | ||
|  | // You should have received a copy of the GNU Lesser General Public License | ||
|  | // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. | ||
|  | 
 | ||
|  | package keystore | ||
|  | 
 | ||
|  | import ( | ||
|  | 	"io/ioutil" | ||
|  | 	"os" | ||
|  | 	"path/filepath" | ||
|  | 	"strings" | ||
|  | 	"sync" | ||
|  | 	"time" | ||
|  | 
 | ||
|  | 	"github.com/ethereum/go-ethereum/log" | ||
|  | 	set "gopkg.in/fatih/set.v0" | ||
|  | ) | ||
|  | 
 | ||
|  | // fileCache is a cache of files seen during scan of keystore. | ||
|  | type fileCache struct { | ||
|  | 	all     *set.SetNonTS // Set of all files from the keystore folder | ||
|  | 	lastMod time.Time     // Last time instance when a file was modified | ||
|  | 	mu      sync.RWMutex | ||
|  | } | ||
|  | 
 | ||
|  | // scan performs a new scan on the given directory, compares against the already | ||
|  | // cached filenames, and returns file sets: creates, deletes, updates. | ||
|  | func (fc *fileCache) scan(keyDir string) (set.Interface, set.Interface, set.Interface, error) { | ||
|  | 	t0 := time.Now() | ||
|  | 
 | ||
|  | 	// List all the failes from the keystore folder | ||
|  | 	files, err := ioutil.ReadDir(keyDir) | ||
|  | 	if err != nil { | ||
|  | 		return nil, nil, nil, err | ||
|  | 	} | ||
|  | 	t1 := time.Now() | ||
|  | 
 | ||
|  | 	fc.mu.Lock() | ||
|  | 	defer fc.mu.Unlock() | ||
|  | 
 | ||
|  | 	// Iterate all the files and gather their metadata | ||
|  | 	all := set.NewNonTS() | ||
|  | 	mods := set.NewNonTS() | ||
|  | 
 | ||
|  | 	var newLastMod time.Time | ||
|  | 	for _, fi := range files { | ||
|  | 		// Skip any non-key files from the folder | ||
|  | 		path := filepath.Join(keyDir, fi.Name()) | ||
|  | 		if skipKeyFile(fi) { | ||
|  | 			log.Trace("Ignoring file on account scan", "path", path) | ||
|  | 			continue | ||
|  | 		} | ||
|  | 		// Gather the set of all and fresly modified files | ||
|  | 		all.Add(path) | ||
|  | 
 | ||
|  | 		modified := fi.ModTime() | ||
|  | 		if modified.After(fc.lastMod) { | ||
|  | 			mods.Add(path) | ||
|  | 		} | ||
|  | 		if modified.After(newLastMod) { | ||
|  | 			newLastMod = modified | ||
|  | 		} | ||
|  | 	} | ||
|  | 	t2 := time.Now() | ||
|  | 
 | ||
|  | 	// Update the tracked files and return the three sets | ||
|  | 	deletes := set.Difference(fc.all, all)   // Deletes = previous - current | ||
|  | 	creates := set.Difference(all, fc.all)   // Creates = current - previous | ||
|  | 	updates := set.Difference(mods, creates) // Updates = modified - creates | ||
|  | 
 | ||
|  | 	fc.all, fc.lastMod = all, newLastMod | ||
|  | 	t3 := time.Now() | ||
|  | 
 | ||
|  | 	// Report on the scanning stats and return | ||
|  | 	log.Debug("FS scan times", "list", t1.Sub(t0), "set", t2.Sub(t1), "diff", t3.Sub(t2)) | ||
|  | 	return creates, deletes, updates, nil | ||
|  | } | ||
|  | 
 | ||
|  | // skipKeyFile ignores editor backups, hidden files and folders/symlinks. | ||
|  | func skipKeyFile(fi os.FileInfo) bool { | ||
|  | 	// Skip editor backups and UNIX-style hidden files. | ||
|  | 	if strings.HasSuffix(fi.Name(), "~") || strings.HasPrefix(fi.Name(), ".") { | ||
|  | 		return true | ||
|  | 	} | ||
|  | 	// Skip misc special files, directories (yes, symlinks too). | ||
|  | 	if fi.IsDir() || fi.Mode()&os.ModeType != 0 { | ||
|  | 		return true | ||
|  | 	} | ||
|  | 	return false | ||
|  | } |