1'use strict' 2 3const cp = require('child_process') 4const path = require('path') 5const { openSync, closeSync } = require('graceful-fs') 6const log = require('./log') 7 8const execFile = async (...args) => new Promise((resolve) => { 9 const child = cp.execFile(...args, (...a) => resolve(a)) 10 child.stdin.end() 11}) 12 13async function regGetValue (key, value, addOpts) { 14 const outReValue = value.replace(/\W/g, '.') 15 const outRe = new RegExp(`^\\s+${outReValue}\\s+REG_\\w+\\s+(\\S.*)$`, 'im') 16 const reg = path.join(process.env.SystemRoot, 'System32', 'reg.exe') 17 const regArgs = ['query', key, '/v', value].concat(addOpts) 18 19 log.silly('reg', 'running', reg, regArgs) 20 const [err, stdout, stderr] = await execFile(reg, regArgs, { encoding: 'utf8' }) 21 22 log.silly('reg', 'reg.exe stdout = %j', stdout) 23 if (err || stderr.trim() !== '') { 24 log.silly('reg', 'reg.exe err = %j', err && (err.stack || err)) 25 log.silly('reg', 'reg.exe stderr = %j', stderr) 26 if (err) { 27 throw err 28 } 29 throw new Error(stderr) 30 } 31 32 const result = outRe.exec(stdout) 33 if (!result) { 34 log.silly('reg', 'error parsing stdout') 35 throw new Error('Could not parse output of reg.exe') 36 } 37 38 log.silly('reg', 'found: %j', result[1]) 39 return result[1] 40} 41 42async function regSearchKeys (keys, value, addOpts) { 43 for (const key of keys) { 44 try { 45 return await regGetValue(key, value, addOpts) 46 } catch { 47 continue 48 } 49 } 50} 51 52/** 53 * Returns the first file or directory from an array of candidates that is 54 * readable by the current user, or undefined if none of the candidates are 55 * readable. 56 */ 57function findAccessibleSync (logprefix, dir, candidates) { 58 for (let next = 0; next < candidates.length; next++) { 59 const candidate = path.resolve(dir, candidates[next]) 60 let fd 61 try { 62 fd = openSync(candidate, 'r') 63 } catch (e) { 64 // this candidate was not found or not readable, do nothing 65 log.silly(logprefix, 'Could not open %s: %s', candidate, e.message) 66 continue 67 } 68 closeSync(fd) 69 log.silly(logprefix, 'Found readable %s', candidate) 70 return candidate 71 } 72 73 return undefined 74} 75 76module.exports = { 77 execFile, 78 regGetValue, 79 regSearchKeys, 80 findAccessibleSync 81} 82