registry.js 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994
  1. /************************************************************************************************************
  2. * registry.js - contains a wrapper for the REG command under Windows, which provides access to the registry
  3. *
  4. * @author Paul Bottin a/k/a FrEsC
  5. *
  6. */
  7. /* imports */
  8. var util = require('util')
  9. , path = require('path')
  10. , spawn = require('child_process').spawn
  11. /* set to console.log for debugging */
  12. , log = function () {}
  13. /* registry hive ids */
  14. , HKLM = 'HKLM'
  15. , HKCU = 'HKCU'
  16. , HKCR = 'HKCR'
  17. , HKU = 'HKU'
  18. , HKCC = 'HKCC'
  19. , HIVES = [ HKLM, HKCU, HKCR, HKU, HKCC ]
  20. /* registry value type ids */
  21. , REG_SZ = 'REG_SZ'
  22. , REG_MULTI_SZ = 'REG_MULTI_SZ'
  23. , REG_EXPAND_SZ = 'REG_EXPAND_SZ'
  24. , REG_DWORD = 'REG_DWORD'
  25. , REG_QWORD = 'REG_QWORD'
  26. , REG_BINARY = 'REG_BINARY'
  27. , REG_NONE = 'REG_NONE'
  28. , REG_TYPES = [ REG_SZ, REG_MULTI_SZ, REG_EXPAND_SZ, REG_DWORD, REG_QWORD, REG_BINARY, REG_NONE ]
  29. /* default registry value name */
  30. , DEFAULT_VALUE = ''
  31. /* general key pattern */
  32. , KEY_PATTERN = /(\\[a-zA-Z0-9_\s]+)*/
  33. /* key path pattern (as returned by REG-cli) */
  34. , PATH_PATTERN = /^(HKEY_LOCAL_MACHINE|HKEY_CURRENT_USER|HKEY_CLASSES_ROOT|HKEY_USERS|HKEY_CURRENT_CONFIG)(.*)$/
  35. /* registry item pattern */
  36. , ITEM_PATTERN = /^(.*)\s(REG_SZ|REG_MULTI_SZ|REG_EXPAND_SZ|REG_DWORD|REG_QWORD|REG_BINARY|REG_NONE)\s+([^\s].*)$/
  37. /**
  38. * Creates an Error object that contains the exit code of the REG.EXE process.
  39. * This contructor is private. Objects of this type are created internally and returned in the <code>err</code> parameters in case the REG.EXE process doesn't exit cleanly.
  40. *
  41. * @private
  42. * @class
  43. *
  44. * @param {string} message - the error message
  45. * @param {number} code - the process exit code
  46. *
  47. */
  48. function ProcessUncleanExitError(message, code) {
  49. if (!(this instanceof ProcessUncleanExitError))
  50. return new ProcessUncleanExitError(message, code);
  51. Error.captureStackTrace(this, ProcessUncleanExitError);
  52. /**
  53. * The error name.
  54. * @readonly
  55. * @member {string} ProcessUncleanExitError#name
  56. */
  57. this.__defineGetter__('name', function () { return ProcessUncleanExitError.name; });
  58. /**
  59. * The error message.
  60. * @readonly
  61. * @member {string} ProcessUncleanExitError#message
  62. */
  63. this.__defineGetter__('message', function () { return message; });
  64. /**
  65. * The process exit code.
  66. * @readonly
  67. * @member {number} ProcessUncleanExitError#code
  68. */
  69. this.__defineGetter__('code', function () { return code; });
  70. }
  71. util.inherits(ProcessUncleanExitError, Error);
  72. /*
  73. * Captures stdout/stderr for a child process
  74. */
  75. function captureOutput(child) {
  76. // Use a mutable data structure so we can append as we get new data and have
  77. // the calling context see the new data
  78. var output = {'stdout': '', 'stderr': ''};
  79. child.stdout.on('data', function(data) { output["stdout"] += data.toString(); });
  80. child.stderr.on('data', function(data) { output["stderr"] += data.toString(); });
  81. return output;
  82. }
  83. /*
  84. * Returns an error message containing the stdout/stderr of the child process
  85. */
  86. function mkErrorMsg(registryCommand, code, output) {
  87. var stdout = output['stdout'].trim();
  88. var stderr = output['stderr'].trim();
  89. var msg = util.format("%s command exited with code %d:\n%s\n%s", registryCommand, code, stdout, stderr);
  90. return new ProcessUncleanExitError(msg, code);
  91. }
  92. /*
  93. * Converts x86/x64 to 32/64
  94. */
  95. function convertArchString(archString) {
  96. if (archString == 'x64') {
  97. return '64';
  98. } else if (archString == 'x86') {
  99. return '32';
  100. } else {
  101. throw new Error('illegal architecture: ' + archString + ' (use x86 or x64)');
  102. }
  103. }
  104. /*
  105. * Adds correct architecture to reg args
  106. */
  107. function pushArch(args, arch) {
  108. if (arch) {
  109. args.push('/reg:' + convertArchString(arch));
  110. }
  111. }
  112. /*
  113. * Get the path to system's reg.exe. Useful when another reg.exe is added to the PATH
  114. * Implemented only for Windows
  115. */
  116. function getRegExePath() {
  117. if (process.platform === 'win32') {
  118. return path.join(process.env.windir, 'system32', 'reg.exe');
  119. } else {
  120. return "REG";
  121. }
  122. }
  123. /**
  124. * Creates a single registry value record.
  125. * This contructor is private. Objects of this type are created internally and returned by methods of {@link Registry} objects.
  126. *
  127. * @private
  128. * @class
  129. *
  130. * @param {string} host - the hostname
  131. * @param {string} hive - the hive id
  132. * @param {string} key - the registry key
  133. * @param {string} name - the value name
  134. * @param {string} type - the value type
  135. * @param {string} value - the value
  136. * @param {string} arch - the hive architecture ('x86' or 'x64')
  137. *
  138. */
  139. function RegistryItem (host, hive, key, name, type, value, arch) {
  140. if (!(this instanceof RegistryItem))
  141. return new RegistryItem(host, hive, key, name, type, value, arch);
  142. /* private members */
  143. var _host = host // hostname
  144. , _hive = hive // registry hive
  145. , _key = key // registry key
  146. , _name = name // property name
  147. , _type = type // property type
  148. , _value = value // property value
  149. , _arch = arch // hive architecture
  150. /* getters/setters */
  151. /**
  152. * The hostname.
  153. * @readonly
  154. * @member {string} RegistryItem#host
  155. */
  156. this.__defineGetter__('host', function () { return _host; });
  157. /**
  158. * The hive id.
  159. * @readonly
  160. * @member {string} RegistryItem#hive
  161. */
  162. this.__defineGetter__('hive', function () { return _hive; });
  163. /**
  164. * The registry key.
  165. * @readonly
  166. * @member {string} RegistryItem#key
  167. */
  168. this.__defineGetter__('key', function () { return _key; });
  169. /**
  170. * The value name.
  171. * @readonly
  172. * @member {string} RegistryItem#name
  173. */
  174. this.__defineGetter__('name', function () { return _name; });
  175. /**
  176. * The value type.
  177. * @readonly
  178. * @member {string} RegistryItem#type
  179. */
  180. this.__defineGetter__('type', function () { return _type; });
  181. /**
  182. * The value.
  183. * @readonly
  184. * @member {string} RegistryItem#value
  185. */
  186. this.__defineGetter__('value', function () { return _value; });
  187. /**
  188. * The hive architecture.
  189. * @readonly
  190. * @member {string} RegistryItem#arch
  191. */
  192. this.__defineGetter__('arch', function () { return _arch; });
  193. }
  194. util.inherits(RegistryItem, Object);
  195. /**
  196. * Creates a registry object, which provides access to a single registry key.
  197. * Note: This class is returned by a call to ```require('winreg')```.
  198. *
  199. * @public
  200. * @class
  201. *
  202. * @param {object} options - the options
  203. * @param {string=} options.host - the hostname
  204. * @param {string=} options.hive - the hive id
  205. * @param {string=} options.key - the registry key
  206. * @param {string=} options.arch - the optional registry hive architecture ('x86' or 'x64'; only valid on Windows 64 Bit Operating Systems)
  207. *
  208. * @example
  209. * var Registry = require('winreg')
  210. * , autoStartCurrentUser = new Registry({
  211. * hive: Registry.HKCU,
  212. * key: '\\Software\\Microsoft\\Windows\\CurrentVersion\\Run'
  213. * });
  214. *
  215. */
  216. function Registry (options) {
  217. if (!(this instanceof Registry))
  218. return new Registry(options);
  219. /* private members */
  220. var _options = options || {}
  221. , _host = '' + (_options.host || '') // hostname
  222. , _hive = '' + (_options.hive || HKLM) // registry hive
  223. , _key = '' + (_options.key || '') // registry key
  224. , _arch = _options.arch || null // hive architecture
  225. /* getters/setters */
  226. /**
  227. * The hostname.
  228. * @readonly
  229. * @member {string} Registry#host
  230. */
  231. this.__defineGetter__('host', function () { return _host; });
  232. /**
  233. * The hive id.
  234. * @readonly
  235. * @member {string} Registry#hive
  236. */
  237. this.__defineGetter__('hive', function () { return _hive; });
  238. /**
  239. * The registry key name.
  240. * @readonly
  241. * @member {string} Registry#key
  242. */
  243. this.__defineGetter__('key', function () { return _key; });
  244. /**
  245. * The full path to the registry key.
  246. * @readonly
  247. * @member {string} Registry#path
  248. */
  249. this.__defineGetter__('path', function () { return (_host.length == 0 ? '' : '\\\\' + _host + '\\') + _hive + _key; });
  250. /**
  251. * The registry hive architecture ('x86' or 'x64').
  252. * @readonly
  253. * @member {string} Registry#arch
  254. */
  255. this.__defineGetter__('arch', function () { return _arch; });
  256. /**
  257. * Creates a new {@link Registry} instance that points to the parent registry key.
  258. * @readonly
  259. * @member {Registry} Registry#parent
  260. */
  261. this.__defineGetter__('parent', function () {
  262. var i = _key.lastIndexOf('\\')
  263. return new Registry({
  264. host: this.host,
  265. hive: this.hive,
  266. key: (i == -1)?'':_key.substring(0, i),
  267. arch: this.arch
  268. });
  269. });
  270. // validate options...
  271. if (HIVES.indexOf(_hive) == -1)
  272. throw new Error('illegal hive specified.');
  273. if (!KEY_PATTERN.test(_key))
  274. throw new Error('illegal key specified.');
  275. if (_arch && _arch != 'x64' && _arch != 'x86')
  276. throw new Error('illegal architecture specified (use x86 or x64)');
  277. }
  278. /**
  279. * Registry hive key HKEY_LOCAL_MACHINE.
  280. * Note: For writing to this hive your program has to run with admin privileges.
  281. * @type {string}
  282. */
  283. Registry.HKLM = HKLM;
  284. /**
  285. * Registry hive key HKEY_CURRENT_USER.
  286. * @type {string}
  287. */
  288. Registry.HKCU = HKCU;
  289. /**
  290. * Registry hive key HKEY_CLASSES_ROOT.
  291. * Note: For writing to this hive your program has to run with admin privileges.
  292. * @type {string}
  293. */
  294. Registry.HKCR = HKCR;
  295. /**
  296. * Registry hive key HKEY_USERS.
  297. * Note: For writing to this hive your program has to run with admin privileges.
  298. * @type {string}
  299. */
  300. Registry.HKU = HKU;
  301. /**
  302. * Registry hive key HKEY_CURRENT_CONFIG.
  303. * Note: For writing to this hive your program has to run with admin privileges.
  304. * @type {string}
  305. */
  306. Registry.HKCC = HKCC;
  307. /**
  308. * Collection of available registry hive keys.
  309. * @type {array}
  310. */
  311. Registry.HIVES = HIVES;
  312. /**
  313. * Registry value type STRING.
  314. * @type {string}
  315. */
  316. Registry.REG_SZ = REG_SZ;
  317. /**
  318. * Registry value type MULTILINE_STRING.
  319. * @type {string}
  320. */
  321. Registry.REG_MULTI_SZ = REG_MULTI_SZ;
  322. /**
  323. * Registry value type EXPANDABLE_STRING.
  324. * @type {string}
  325. */
  326. Registry.REG_EXPAND_SZ = REG_EXPAND_SZ;
  327. /**
  328. * Registry value type DOUBLE_WORD.
  329. * @type {string}
  330. */
  331. Registry.REG_DWORD = REG_DWORD;
  332. /**
  333. * Registry value type QUAD_WORD.
  334. * @type {string}
  335. */
  336. Registry.REG_QWORD = REG_QWORD;
  337. /**
  338. * Registry value type BINARY.
  339. * @type {string}
  340. */
  341. Registry.REG_BINARY = REG_BINARY;
  342. /**
  343. * Registry value type UNKNOWN.
  344. * @type {string}
  345. */
  346. Registry.REG_NONE = REG_NONE;
  347. /**
  348. * Collection of available registry value types.
  349. * @type {array}
  350. */
  351. Registry.REG_TYPES = REG_TYPES;
  352. /**
  353. * The name of the default value. May be used instead of the empty string literal for better readability.
  354. * @type {string}
  355. */
  356. Registry.DEFAULT_VALUE = DEFAULT_VALUE;
  357. /**
  358. * Retrieve all values from this registry key.
  359. * @param {valuesCallback} cb - callback function
  360. * @param {ProcessUncleanExitError=} cb.err - error object or null if successful
  361. * @param {array=} cb.items - an array of {@link RegistryItem} objects
  362. * @returns {Registry} this registry key object
  363. */
  364. Registry.prototype.values = function values (cb) {
  365. if (typeof cb !== 'function')
  366. throw new TypeError('must specify a callback');
  367. var args = [ 'QUERY', this.path ];
  368. pushArch(args, this.arch);
  369. var proc = spawn(getRegExePath(), args, {
  370. cwd: undefined,
  371. env: process.env,
  372. stdio: [ 'ignore', 'pipe', 'pipe' ]
  373. })
  374. , buffer = ''
  375. , self = this
  376. , error = null // null means no error previously reported.
  377. var output = captureOutput(proc);
  378. proc.on('close', function (code) {
  379. if (error) {
  380. return;
  381. } else if (code !== 0) {
  382. log('process exited with code ' + code);
  383. cb(mkErrorMsg('QUERY', code, output), null);
  384. } else {
  385. var items = []
  386. , result = []
  387. , lines = buffer.split('\n')
  388. , lineNumber = 0
  389. for (var i = 0, l = lines.length; i < l; i++) {
  390. var line = lines[i].trim();
  391. if (line.length > 0) {
  392. log(line);
  393. if (lineNumber != 0) {
  394. items.push(line);
  395. }
  396. ++lineNumber;
  397. }
  398. }
  399. for (var i = 0, l = items.length; i < l; i++) {
  400. var match = ITEM_PATTERN.exec(items[i])
  401. , name
  402. , type
  403. , value
  404. if (match) {
  405. name = match[1].trim();
  406. type = match[2].trim();
  407. value = match[3];
  408. result.push(new RegistryItem(self.host, self.hive, self.key, name, type, value, self.arch));
  409. }
  410. }
  411. cb(null, result);
  412. }
  413. });
  414. proc.stdout.on('data', function (data) {
  415. buffer += data.toString();
  416. });
  417. proc.on('error', function(err) {
  418. error = err;
  419. cb(err);
  420. });
  421. return this;
  422. };
  423. /**
  424. * Retrieve all subkeys from this registry key.
  425. * @param {function (err, items)} cb - callback function
  426. * @param {ProcessUncleanExitError=} cb.err - error object or null if successful
  427. * @param {array=} cb.items - an array of {@link Registry} objects
  428. * @returns {Registry} this registry key object
  429. */
  430. Registry.prototype.keys = function keys (cb) {
  431. if (typeof cb !== 'function')
  432. throw new TypeError('must specify a callback');
  433. var args = [ 'QUERY', this.path ];
  434. pushArch(args, this.arch);
  435. var proc = spawn(getRegExePath(), args, {
  436. cwd: undefined,
  437. env: process.env,
  438. stdio: [ 'ignore', 'pipe', 'pipe' ]
  439. })
  440. , buffer = ''
  441. , self = this
  442. , error = null // null means no error previously reported.
  443. var output = captureOutput(proc);
  444. proc.on('close', function (code) {
  445. if (error) {
  446. return;
  447. } else if (code !== 0) {
  448. log('process exited with code ' + code);
  449. cb(mkErrorMsg('QUERY', code, output), null);
  450. }
  451. });
  452. proc.stdout.on('data', function (data) {
  453. buffer += data.toString();
  454. });
  455. proc.stdout.on('end', function () {
  456. var items = []
  457. , result = []
  458. , lines = buffer.split('\n')
  459. for (var i = 0, l = lines.length; i < l; i++) {
  460. var line = lines[i].trim();
  461. if (line.length > 0) {
  462. log(line);
  463. items.push(line);
  464. }
  465. }
  466. for (var i = 0, l = items.length; i < l; i++) {
  467. var match = PATH_PATTERN.exec(items[i])
  468. , hive
  469. , key
  470. if (match) {
  471. hive = match[1];
  472. key = match[2];
  473. if (key && (key !== self.key)) {
  474. result.push(new Registry({
  475. host: self.host,
  476. hive: self.hive,
  477. key: key,
  478. arch: self.arch
  479. }));
  480. }
  481. }
  482. }
  483. cb(null, result);
  484. });
  485. proc.on('error', function(err) {
  486. error = err;
  487. cb(err);
  488. });
  489. return this;
  490. };
  491. /**
  492. * Gets a named value from this registry key.
  493. * @param {string} name - the value name, use {@link Registry.DEFAULT_VALUE} or an empty string for the default value
  494. * @param {function (err, item)} cb - callback function
  495. * @param {ProcessUncleanExitError=} cb.err - error object or null if successful
  496. * @param {RegistryItem=} cb.item - the retrieved registry item
  497. * @returns {Registry} this registry key object
  498. */
  499. Registry.prototype.get = function get (name, cb) {
  500. if (typeof cb !== 'function')
  501. throw new TypeError('must specify a callback');
  502. var args = ['QUERY', this.path];
  503. if (name == '')
  504. args.push('/ve');
  505. else
  506. args = args.concat(['/v', name]);
  507. pushArch(args, this.arch);
  508. var proc = spawn(getRegExePath(), args, {
  509. cwd: undefined,
  510. env: process.env,
  511. stdio: [ 'ignore', 'pipe', 'pipe' ]
  512. })
  513. , buffer = ''
  514. , self = this
  515. , error = null // null means no error previously reported.
  516. var output = captureOutput(proc);
  517. proc.on('close', function (code) {
  518. if (error) {
  519. return;
  520. } else if (code !== 0) {
  521. log('process exited with code ' + code);
  522. cb(mkErrorMsg('QUERY', code, output), null);
  523. } else {
  524. var items = []
  525. , result = null
  526. , lines = buffer.split('\n')
  527. , lineNumber = 0
  528. for (var i = 0, l = lines.length; i < l; i++) {
  529. var line = lines[i].trim();
  530. if (line.length > 0) {
  531. log(line);
  532. if (lineNumber != 0) {
  533. items.push(line);
  534. }
  535. ++lineNumber;
  536. }
  537. }
  538. //Get last item - so it works in XP where REG QUERY returns with a header
  539. var item = items[items.length-1] || ''
  540. , match = ITEM_PATTERN.exec(item)
  541. , name
  542. , type
  543. , value
  544. if (match) {
  545. name = match[1].trim();
  546. type = match[2].trim();
  547. value = match[3];
  548. result = new RegistryItem(self.host, self.hive, self.key, name, type, value, self.arch);
  549. }
  550. cb(null, result);
  551. }
  552. });
  553. proc.stdout.on('data', function (data) {
  554. buffer += data.toString();
  555. });
  556. proc.on('error', function(err) {
  557. error = err;
  558. cb(err);
  559. });
  560. return this;
  561. };
  562. /**
  563. * Sets a named value in this registry key, overwriting an already existing value.
  564. * @param {string} name - the value name, use {@link Registry.DEFAULT_VALUE} or an empty string for the default value
  565. * @param {string} type - the value type
  566. * @param {string} value - the value
  567. * @param {function (err)} cb - callback function
  568. * @param {ProcessUncleanExitError=} cb.err - error object or null if successful
  569. * @returns {Registry} this registry key object
  570. */
  571. Registry.prototype.set = function set (name, type, value, cb) {
  572. if (typeof cb !== 'function')
  573. throw new TypeError('must specify a callback');
  574. if (REG_TYPES.indexOf(type) == -1)
  575. throw Error('illegal type specified.');
  576. var args = ['ADD', this.path];
  577. if (name == '')
  578. args.push('/ve');
  579. else
  580. args = args.concat(['/v', name]);
  581. args = args.concat(['/t', type, '/d', value, '/f']);
  582. pushArch(args, this.arch);
  583. var proc = spawn(getRegExePath(), args, {
  584. cwd: undefined,
  585. env: process.env,
  586. stdio: [ 'ignore', 'pipe', 'pipe' ]
  587. })
  588. , error = null // null means no error previously reported.
  589. var output = captureOutput(proc);
  590. proc.on('close', function (code) {
  591. if(error) {
  592. return;
  593. } else if (code !== 0) {
  594. log('process exited with code ' + code);
  595. cb(mkErrorMsg('ADD', code, output, null));
  596. } else {
  597. cb(null);
  598. }
  599. });
  600. proc.stdout.on('data', function (data) {
  601. // simply discard output
  602. log(''+data);
  603. });
  604. proc.on('error', function(err) {
  605. error = err;
  606. cb(err);
  607. });
  608. return this;
  609. };
  610. /**
  611. * Remove a named value from this registry key. If name is empty, sets the default value of this key.
  612. * Note: This key must be already existing.
  613. * @param {string} name - the value name, use {@link Registry.DEFAULT_VALUE} or an empty string for the default value
  614. * @param {function (err)} cb - callback function
  615. * @param {ProcessUncleanExitError=} cb.err - error object or null if successful
  616. * @returns {Registry} this registry key object
  617. */
  618. Registry.prototype.remove = function remove (name, cb) {
  619. if (typeof cb !== 'function')
  620. throw new TypeError('must specify a callback');
  621. var args = name ? ['DELETE', this.path, '/f', '/v', name] : ['DELETE', this.path, '/f', '/ve'];
  622. pushArch(args, this.arch);
  623. var proc = spawn(getRegExePath(), args, {
  624. cwd: undefined,
  625. env: process.env,
  626. stdio: [ 'ignore', 'pipe', 'pipe' ]
  627. })
  628. , error = null // null means no error previously reported.
  629. var output = captureOutput(proc);
  630. proc.on('close', function (code) {
  631. if(error) {
  632. return;
  633. } else if (code !== 0) {
  634. log('process exited with code ' + code);
  635. cb(mkErrorMsg('DELETE', code, output), null);
  636. } else {
  637. cb(null);
  638. }
  639. });
  640. proc.stdout.on('data', function (data) {
  641. // simply discard output
  642. log(''+data);
  643. });
  644. proc.on('error', function(err) {
  645. error = err;
  646. cb(err);
  647. });
  648. return this;
  649. };
  650. /**
  651. * Remove all subkeys and values (including the default value) from this registry key.
  652. * @param {function (err)} cb - callback function
  653. * @param {ProcessUncleanExitError=} cb.err - error object or null if successful
  654. * @returns {Registry} this registry key object
  655. */
  656. Registry.prototype.clear = function clear (cb) {
  657. if (typeof cb !== 'function')
  658. throw new TypeError('must specify a callback');
  659. var args = ['DELETE', this.path, '/f', '/va'];
  660. pushArch(args, this.arch);
  661. var proc = spawn(getRegExePath(), args, {
  662. cwd: undefined,
  663. env: process.env,
  664. stdio: [ 'ignore', 'pipe', 'pipe' ]
  665. })
  666. , error = null // null means no error previously reported.
  667. var output = captureOutput(proc);
  668. proc.on('close', function (code) {
  669. if(error) {
  670. return;
  671. } else if (code !== 0) {
  672. log('process exited with code ' + code);
  673. cb(mkErrorMsg("DELETE", code, output), null);
  674. } else {
  675. cb(null);
  676. }
  677. });
  678. proc.stdout.on('data', function (data) {
  679. // simply discard output
  680. log(''+data);
  681. });
  682. proc.on('error', function(err) {
  683. error = err;
  684. cb(err);
  685. });
  686. return this;
  687. };
  688. /**
  689. * Alias for the clear method to keep it backward compatible.
  690. * @method
  691. * @deprecated Use {@link Registry#clear} or {@link Registry#destroy} in favour of this method.
  692. * @param {function (err)} cb - callback function
  693. * @param {ProcessUncleanExitError=} cb.err - error object or null if successful
  694. * @returns {Registry} this registry key object
  695. */
  696. Registry.prototype.erase = Registry.prototype.clear;
  697. /**
  698. * Delete this key and all subkeys from the registry.
  699. * @param {function (err)} cb - callback function
  700. * @param {ProcessUncleanExitError=} cb.err - error object or null if successful
  701. * @returns {Registry} this registry key object
  702. */
  703. Registry.prototype.destroy = function destroy (cb) {
  704. if (typeof cb !== 'function')
  705. throw new TypeError('must specify a callback');
  706. var args = ['DELETE', this.path, '/f'];
  707. pushArch(args, this.arch);
  708. var proc = spawn(getRegExePath(), args, {
  709. cwd: undefined,
  710. env: process.env,
  711. stdio: [ 'ignore', 'pipe', 'pipe' ]
  712. })
  713. , error = null // null means no error previously reported.
  714. var output = captureOutput(proc);
  715. proc.on('close', function (code) {
  716. if (error) {
  717. return;
  718. } else if (code !== 0) {
  719. log('process exited with code ' + code);
  720. cb(mkErrorMsg('DELETE', code, output), null);
  721. } else {
  722. cb(null);
  723. }
  724. });
  725. proc.stdout.on('data', function (data) {
  726. // simply discard output
  727. log(''+data);
  728. });
  729. proc.on('error', function(err) {
  730. error = err;
  731. cb(err);
  732. });
  733. return this;
  734. };
  735. /**
  736. * Create this registry key. Note that this is a no-op if the key already exists.
  737. * @param {function (err)} cb - callback function
  738. * @param {ProcessUncleanExitError=} cb.err - error object or null if successful
  739. * @returns {Registry} this registry key object
  740. */
  741. Registry.prototype.create = function create (cb) {
  742. if (typeof cb !== 'function')
  743. throw new TypeError('must specify a callback');
  744. var args = ['ADD', this.path, '/f'];
  745. pushArch(args, this.arch);
  746. var proc = spawn(getRegExePath(), args, {
  747. cwd: undefined,
  748. env: process.env,
  749. stdio: [ 'ignore', 'pipe', 'pipe' ]
  750. })
  751. , error = null // null means no error previously reported.
  752. var output = captureOutput(proc);
  753. proc.on('close', function (code) {
  754. if (error) {
  755. return;
  756. } else if (code !== 0) {
  757. log('process exited with code ' + code);
  758. cb(mkErrorMsg('ADD', code, output), null);
  759. } else {
  760. cb(null);
  761. }
  762. });
  763. proc.stdout.on('data', function (data) {
  764. // simply discard output
  765. log(''+data);
  766. });
  767. proc.on('error', function(err) {
  768. error = err;
  769. cb(err);
  770. });
  771. return this;
  772. };
  773. /**
  774. * Checks if this key already exists.
  775. * @param {function (err, exists)} cb - callback function
  776. * @param {ProcessUncleanExitError=} cb.err - error object or null if successful
  777. * @param {boolean=} cb.exists - true if a registry key with this name already exists
  778. * @returns {Registry} this registry key object
  779. */
  780. Registry.prototype.keyExists = function keyExists (cb) {
  781. this.values(function (err, items) {
  782. if (err) {
  783. // process should return with code 1 if key not found
  784. if (err.code == 1) {
  785. return cb(null, false);
  786. }
  787. // other error
  788. return cb(err);
  789. }
  790. cb(null, true);
  791. });
  792. return this;
  793. };
  794. /**
  795. * Checks if a value with the given name already exists within this key.
  796. * @param {string} name - the value name, use {@link Registry.DEFAULT_VALUE} or an empty string for the default value
  797. * @param {function (err, exists)} cb - callback function
  798. * @param {ProcessUncleanExitError=} cb.err - error object or null if successful
  799. * @param {boolean=} cb.exists - true if a value with the given name was found in this key
  800. * @returns {Registry} this registry key object
  801. */
  802. Registry.prototype.valueExists = function valueExists (name, cb) {
  803. this.get(name, function (err, item) {
  804. if (err) {
  805. // process should return with code 1 if value not found
  806. if (err.code == 1) {
  807. return cb(null, false);
  808. }
  809. // other error
  810. return cb(err);
  811. }
  812. cb(null, true);
  813. });
  814. return this;
  815. };
  816. module.exports = Registry;