//Back to tutorial
//Copy following code and paste into walker.js file (CTRL + A to select all then CTRL + C to copy):
//walker.js const fs = require('fs'), crypto = require('crypto'), path = require('path'), {EventEmitter} = require('events'); module.exports = class FileWalker extends EventEmitter { constructor (debug){ super(); this.debug = debug ? true : false; this.reset(debug); } reset(){ this.isPaused = false; this.queue = []; this.filter_dir = () => false; this.filter_file = () => false; } addToQueue(entry){ Array.isArray(entry) ? Array.prototype.push.apply (this.queue, entry) : this.queue.push (entry) } filterDir (fn){ this.filter_dir = fn; } filterFile (fn){ this.filter_file = fn; } start (entry) { fs.lstat(entry, (err,stat) => { if (err){ this.debug&&console.log('Error stat: '+entry); this.emit('error',err,entry,stat); return this.next(); } if (stat.isFile()){ if (this.filter_file(entry,stat)){ this.debug&&console.log('filterFile: '+entry); return this.next(); } this.debug&&console.log('File: '+entry); this.emit('file',entry,stat); this.generateHash(entry,stat);/*Read file header*/ this.next(); } else if (stat.isDirectory()){ if (this.filter_dir(entry,stat)){ this.debug&&console.log('filterDir: '+entry); return this.next(); } this.debug&&console.log('Dir: '+entry); this.emit('dir',entry,stat); fs.readdir(entry, (err,files) => { if (err){ this.debug&&console.log('Error readdir: '+entry); this.emit('error',err,entry,stat); return this.next(); } Array.prototype.push.apply(this.queue, files.map( file => { return path.join(entry,file); })); this.next(); }); } else { this.debug&&console.log('unknown or inaccessilbe: '+entry); this.emit('unknown',entry,stat); this.next() } }); } next(){ if (this.isPaused) { this.emit('pause'); this.debug&&console.log('isPaused, remaining files in queue:'+this.queue.length); return this; } let nextEntry = this.queue.shift(); if (!nextEntry){ this.emit('done'); this.debug&&console.log('Done'); return this; } this.start(nextEntry); } pause(){ if (this.isPaused === true){ debug&&console.log('isPaused failed. App was already paused'); return this; } this.isPaused = true; } resume(){ if (this.isPaused === false){ debug&&console.log('Resume failed. App was already resumed'); return; } this.isPaused = false; this.debug&&console.log('Resume'); this.emit('resume'); this.next(); } generateHash(file,stat){ const defaultLength = 4200, len = stat.size < defaultLength ? stat.size : defaultLength, pos = 0, offset =0; fs.open(file, 'r', (err, fd) => { if (err) { this.emit('error',err,file,stat); this.debug&&console.log(err.message); return; } const buffer = Buffer.alloc(len); fs.read(fd, buffer, offset, len, pos, (err, bytesRead, buffer) => { if (err){ this.emit('error',err,file,stat); this.debug&&console.log(err); return; } fs.close(fd, (err) => { if (err){ this.emit('error',err,file,stat); this.debug&&console.log(err); return; } }); const hash = crypto .createHash('whirlpool') .update(buffer) .digest('hex'); this.emit('hash',file,stat,buffer,hash); this.debug&&console.log('hash emitted'); return; }); }) } }