Repository: raszi/node-tmp
Pull request #234 (2020-02-03 12:45:39)

feat: stabilize tmp for v0.2.0 release
TODO

- [x] #218 - name must be relative and must not contain path components
- [x] #207 - dir must be relative to default tmp
- [x] #246 - quotes in tmp dirname may cause problems
- [x] #237 
- [x] #238
- [x] #236
- [x] #176
- [x] #156
- [x] #240 
- [x] update documentation
- [x] fix failing tests (missing SIGINT handler, console.log in lib/tmp.js)
- [x] remove obsolete tests (safely install listeners)
- [x] further code clean up, use let/const instead of var, get rid of process.bindings reference, prefix private functions with an underscore, stop handling old node <v8 behaviours
- [x] drop support for node < v8.17.0 since eslint will no longer work with e.g. v8.1.3 and I am too lazy to figure out when node v8 introduced deconstruction of arrays
- [x] regression on WIN32 when removing handling for old node behaviour regarding SystemError.errno and .code


Patch:
diff --git a/.travis.yml b/.travis.yml
index 0f4c1ae..c564cc7 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,6 +1,7 @@
 language: node_js
 node_js:
   - "node"
+  - "13"
   - "12"
   - "11"
   - "10"
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e69de29..539dbda 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -0,0 +1,119 @@
+# CHANGELOG
+
+## tmp v0.2.0
+
+- drop support for node version < v8.17.0
+
+  ***BREAKING CHANGE***
+  
+  node versions < v8.17.0 are no longer supported. 
+
+- [#216](https://github.com/raszi/node-tmp/issues/216)
+
+  ***BREAKING CHANGE***
+
+  SIGINT handler has been removed. 
+
+  Users must install their own SIGINT handler and call process.exit() so that tmp's process 
+  exit handler can do the cleanup.
+  
+  A simple handler would be
+  
+  ```
+  process.on('SIGINT', process.exit);
+  ```
+
+- [#156](https://github.com/raszi/node-tmp/issues/156)
+
+  ***BREAKING CHANGE***
+
+  template option no longer accepts arbitrary paths. all paths must be relative to os.tmpdir().
+  the template option can point to an absolute path that is located under os.tmpdir().
+  this can now be used in conjunction with the dir option. 
+
+- [#207](https://github.com/raszi/node-tmp/issues/TBD)
+
+  ***BREAKING CHANGE***
+
+  dir option no longer accepts arbitrary paths. all paths must be relative to os.tmpdir().
+  the dir option can point to an absolute path that is located under os.tmpdir().
+
+- [#218](https://github.com/raszi/node-tmp/issues/TBD)
+
+  ***BREAKING CHANGE***
+
+  name option no longer accepts arbitrary paths. name must no longer contain a path and will always be made relative
+  to the current os.tmpdir() and the optional dir option.
+
+- [#197](https://github.com/raszi/node-tmp/issues/197)
+
+  ***BUG FIX***
+
+  sync cleanup callback must be returned when using the sync API functions.
+  
+  fs.rmdirSync() must not be called with a second parameter that is a function.
+
+- [#176](https://github.com/raszi/node-tmp/issues/176)
+
+  ***BUG FIX***
+
+  fail early if no os.tmpdir() was specified.
+  previous versions of Electron did return undefined when calling os.tmpdir().
+  _getTmpDir() now tries to resolve the path returned by os.tmpdir().
+  
+  now using rimraf for removing directory trees.
+
+- [#246](https://github.com/raszi/node-tmp/issues/246)
+
+  ***BUG FIX***
+
+  os.tmpdir() might return a value that includes single or double quotes,
+  similarly so the dir option, the template option and the name option
+
+- [#240](https://github.com/raszi/node-tmp/issues/240)
+
+  ***DOCUMENTATION***
+  
+  better documentation for `tmp.setGracefulCleanup()`.
+
+- [#206](https://github.com/raszi/node-tmp/issues/206)
+
+  ***DOCUMENTATION***
+  
+  document name option.
+
+- [#236](https://github.com/raszi/node-tmp/issues/236)
+
+  ***DOCUMENTATION***
+
+  document discardDescriptor option.
+
+- [#237](https://github.com/raszi/node-tmp/issues/237)
+
+  ***DOCUMENTATION***
+
+  document detachDescriptor option.
+
+- [#238](https://github.com/raszi/node-tmp/issues/238)
+
+  ***DOCUMENTATION***
+
+  document mode option.
+
+- [#175](https://github.com/raszi/node-tmp/issues/175)
+
+  ***DOCUMENTATION***
+
+  document unsafeCleanup option.
+
+
+### Miscellaneous
+
+- stabilized tests
+- general clean up
+- update jsdoc
+
+
+## Previous Releases
+
+- no information available
diff --git a/README.md b/README.md
index 5e3aeb4..2e5572e 100644
--- a/README.md
+++ b/README.md
@@ -29,6 +29,8 @@ standard OS temporary directory, then you are free to override that as well.
 
 ## An Important Note on Compatibility
 
+See the [CHANGELOG](./CHANGELOG.md) for more information.
+
 ### Version 0.1.0
 
 Since version 0.1.0, all support for node versions < 0.10.0 has been dropped.
@@ -48,15 +50,6 @@ dependency to version 0.0.33.
 For node versions < 0.8 you must limit your node-tmp dependency to
 versions < 0.0.33.
 
-### Node Versions < 8.12.0
-
-The SIGINT handler will not work correctly with versions of NodeJS < 8.12.0.
-
-### Windows
-
-Signal handlers for SIGINT will not work. Pressing CTRL-C will leave behind
-temporary files and directories.
-
 ## How to install
 
 ```bash
@@ -72,7 +65,7 @@ Please also check [API docs][4].
 Simple temporary file creation, the file will be closed and unlinked on process exit.
 
 ```javascript
-var tmp = require('tmp');
+const tmp = require('tmp');
 
 tmp.file(function _tempFileCreated(err, path, fd, cleanupCallback) {
   if (err) throw err;
@@ -92,9 +85,9 @@ tmp.file(function _tempFileCreated(err, path, fd, cleanupCallback) {
 A synchronous version of the above.
 
 ```javascript
-var tmp = require('tmp');
+const tmp = require('tmp');
 
-var tmpobj = tmp.fileSync();
+const tmpobj = tmp.fileSync();
 console.log('File: ', tmpobj.name);
 console.log('Filedescriptor: ', tmpobj.fd);
   
@@ -115,7 +108,7 @@ Simple temporary directory creation, it will be removed on process exit.
 If the directory still contains items on process exit, then it won't be removed.
 
 ```javascript
-var tmp = require('tmp');
+const tmp = require('tmp');
 
 tmp.dir(function _tempDirCreated(err, path, cleanupCallback) {
   if (err) throw err;
@@ -135,9 +128,9 @@ you can pass the `unsafeCleanup` option when creating it.
 A synchronous version of the above.
 
 ```javascript
-var tmp = require('tmp');
+const tmp = require('tmp');
 
-var tmpobj = tmp.dirSync();
+const tmpobj = tmp.dirSync();
 console.log('Dir: ', tmpobj.name);
 // Manual cleanup
 tmpobj.removeCallback();
@@ -153,7 +146,7 @@ It is possible with this library to generate a unique filename in the specified
 directory.
 
 ```javascript
-var tmp = require('tmp');
+const tmp = require('tmp');
 
 tmp.tmpName(function _tempNameGenerated(err, path) {
     if (err) throw err;
@@ -167,9 +160,9 @@ tmp.tmpName(function _tempNameGenerated(err, path) {
 A synchronous version of the above.
 
 ```javascript
-var tmp = require('tmp');
+const tmp = require('tmp');
 
-var name = tmp.tmpNameSync();
+const name = tmp.tmpNameSync();
 console.log('Created temporary filename: ', name);
 ```
 
@@ -180,9 +173,9 @@ console.log('Created temporary filename: ', name);
 Creates a file with mode `0644`, prefix will be `prefix-` and postfix will be `.txt`.
 
 ```javascript
-var tmp = require('tmp');
+const tmp = require('tmp');
 
-tmp.file({ mode: 0644, prefix: 'prefix-', postfix: '.txt' }, function _tempFileCreated(err, path, fd) {
+tmp.file({ mode: 0o644, prefix: 'prefix-', postfix: '.txt' }, function _tempFileCreated(err, path, fd) {
   if (err) throw err;
 
   console.log('File: ', path);
@@ -195,9 +188,9 @@ tmp.file({ mode: 0644, prefix: 'prefix-', postfix: '.txt' }, function _tempFileC
 A synchronous version of the above.
 
 ```javascript
-var tmp = require('tmp');
+const tmp = require('tmp');
 
-var tmpobj = tmp.fileSync({ mode: 0644, prefix: 'prefix-', postfix: '.txt' });
+const tmpobj = tmp.fileSync({ mode: 0o644, prefix: 'prefix-', postfix: '.txt' });
 console.log('File: ', tmpobj.name);
 console.log('Filedescriptor: ', tmpobj.fd);
 ```
@@ -219,7 +212,7 @@ descriptor.  Two options control how the descriptor is managed:
   longer needed.
 
 ```javascript
-var tmp = require('tmp');
+const tmp = require('tmp');
 
 tmp.file({ discardDescriptor: true }, function _tempFileCreated(err, path, fd, cleanupCallback) {
   if (err) throw err;
@@ -229,7 +222,7 @@ tmp.file({ discardDescriptor: true }, function _tempFileCreated(err, path, fd, c
 ```
 
 ```javascript
-var tmp = require('tmp');
+const tmp = require('tmp');
 
 tmp.file({ detachDescriptor: true }, function _tempFileCreated(err, path, fd, cleanupCallback) {
   if (err) throw err;
@@ -246,9 +239,9 @@ tmp.file({ detachDescriptor: true }, function _tempFileCreated(err, path, fd, cl
 Creates a directory with mode `0755`, prefix will be `myTmpDir_`.
 
 ```javascript
-var tmp = require('tmp');
+const tmp = require('tmp');
 
-tmp.dir({ mode: 0750, prefix: 'myTmpDir_' }, function _tempDirCreated(err, path) {
+tmp.dir({ mode: 0o750, prefix: 'myTmpDir_' }, function _tempDirCreated(err, path) {
   if (err) throw err;
 
   console.log('Dir: ', path);
@@ -260,9 +253,9 @@ tmp.dir({ mode: 0750, prefix: 'myTmpDir_' }, function _tempDirCreated(err, path)
 Again, a synchronous version of the above.
 
 ```javascript
-var tmp = require('tmp');
+const tmp = require('tmp');
 
-var tmpobj = tmp.dirSync({ mode: 0750, prefix: 'myTmpDir_' });
+const tmpobj = tmp.dirSync({ mode: 0750, prefix: 'myTmpDir_' });
 console.log('Dir: ', tmpobj.name);
 ```
 
@@ -275,7 +268,7 @@ require tmp to create your temporary filesystem object in a different place than
 default `tmp.tmpdir`.
 
 ```javascript
-var tmp = require('tmp');
+const tmp = require('tmp');
 
 tmp.dir({ template: 'tmp-XXXXXX' }, function _tempDirCreated(err, path) {
   if (err) throw err;
@@ -289,9 +282,9 @@ tmp.dir({ template: 'tmp-XXXXXX' }, function _tempDirCreated(err, path) {
 This will behave similarly to the asynchronous version.
 
 ```javascript
-var tmp = require('tmp');
+const tmp = require('tmp');
 
-var tmpobj = tmp.dirSync({ template: 'tmp-XXXXXX' });
+const tmpobj = tmp.dirSync({ template: 'tmp-XXXXXX' });
 console.log('Dir: ', tmpobj.name);
 ```
 
@@ -303,9 +296,9 @@ The function accepts all standard options, e.g. `prefix`, `postfix`, `dir`, and
 You can also leave out the options altogether and just call the function with a callback as first parameter.
 
 ```javascript
-var tmp = require('tmp');
+const tmp = require('tmp');
 
-var options = {};
+const options = {};
 
 tmp.tmpName(options, function _tempNameGenerated(err, path) {
     if (err) throw err;
@@ -320,19 +313,22 @@ The `tmpNameSync()` function works similarly to `tmpName()`.
 Again, you can leave out the options altogether and just invoke the function without any parameters.
 
 ```javascript
-var tmp = require('tmp');
-var options = {};
-var tmpname = tmp.tmpNameSync(options);
+const tmp = require('tmp');
+const options = {};
+const tmpname = tmp.tmpNameSync(options);
 console.log('Created temporary filename: ', tmpname);
 ```
 
 ## Graceful cleanup
 
-One may want to cleanup the temporary files even when an uncaught exception
-occurs. To enforce this, you can call the `setGracefulCleanup()` method:
+If graceful cleanup is set, tmp will remove all controlled temporary objects on process exit, otherwise the
+temporary objects will remain in place, waiting to be cleaned up on system restart or otherwise scheduled temporary
+object removal.
+
+To enforce this, you can call the `setGracefulCleanup()` method:
 
 ```javascript
-var tmp = require('tmp');
+const tmp = require('tmp');
 
 tmp.setGracefulCleanup();
 ```
@@ -341,16 +337,25 @@ tmp.setGracefulCleanup();
 
 All options are optional :)
 
-  * `name`: a fixed name that overrides random name generation
-  * `mode`: the file mode to create with, it fallbacks to `0600` on file creation and `0700` on directory creation
-  * `prefix`: the optional prefix, fallbacks to `tmp-` if not provided
-  * `postfix`: the optional postfix, fallbacks to `.tmp` on file creation
-  * `template`: [`mkstemp`][3] like filename template, no default
-  * `dir`: the optional temporary directory, fallbacks to system default (guesses from environment)
+  * `name`: a fixed name that overrides random name generation, the name must be relative and must not contain path segments
+  * `mode`: the file mode to create with, falls back to `0o600` on file creation and `0o700` on directory creation
+  * `prefix`: the optional prefix, defaults to `tmp`
+  * `postfix`: the optional postfix
+  * `template`: [`mkstemp`][3] like filename template, no default, can be either an absolute or a relative path that resolves 
+     to a relative path of the system's default temporary directory, must include `XXXXXX` once for random name generation, e.g.
+     'foo/bar/XXXXXX'. Absolute paths are also fine as long as they are relative to os.tmpdir().
+     Any directories along the so specified path must exist, otherwise a ENOENT error will be thrown upon access, 
+     as tmp will not check the availability of the path, nor will it establish the requested path for you. 
+  * `dir`: the optional temporary directory that must be relative to the system's default temporary directory.
+     absolute paths are fine as long as they point to a location under the system's default temporary directory.
+     Any directories along the so specified path must exist, otherwise a ENOENT error will be thrown upon access, 
+     as tmp will not check the availability of the path, nor will it establish the requested path for you.
   * `tries`: how many times should the function try to get a unique filename before giving up, default `3`
   * `keep`: signals that the temporary file or directory should not be deleted on exit, default is `false`
     * In order to clean up, you will have to call the provided `cleanupCallback` function manually.
   * `unsafeCleanup`: recursively removes the created temporary directory, even when it's not empty. default is `false`
+  * `detachDescriptor`: detaches the file descriptor, caller is responsible for closing the file, tmp will no longer try closing the file during garbage collection
+  * `discardDescriptor`: discards the file descriptor (closes file, fd is -1), tmp will no longer try closing the file during garbage collection
 
 [1]: http://nodejs.org/
 [2]: https://www.npmjs.com/browse/depended/tmp
diff --git a/appveyor.yml b/appveyor.yml
index c0d80e6..861edaa 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -7,6 +7,7 @@ environment:
     - nodejs_version: "10"
     - nodejs_version: "11"
     - nodejs_version: "12"
+    - nodejs_version: "13"
 
 install:
   - ps: Install-Product node $env:nodejs_version
diff --git a/docs/global.html b/docs/global.html
index 820fcd7..e225ad4 100644
--- a/docs/global.html
+++ b/docs/global.html
@@ -87,42 +87,6 @@
 
     
 
-     
-
-    
-
-    
-        <h3 class="subsection-title">Members</h3>
-
-        
-            
-<h4 class="name" id="tmpDir"><span class="type-signature">(constant) </span>tmpDir<span class="type-signature"> :string</span></h4>
-
-
-
-
-<div class="description">
-    The temporary directory.
-</div>
-
-
-
-    <h5>Type:</h5>
-    <ul>
-        <li>
-            
-<span class="param-type">string</span>
-
-
-        </li>
-    </ul>
-
-
-
-
-
-<dl class="details">
-
     
 
     
@@ -132,44 +96,6 @@
     
 
     
-
-    
-
-    
-
-    
-
-    
-
-    
-
-    
-
-    
-
-    
-    <dt class="tag-source">Source:</dt>
-    <dd class="tag-source"><ul class="dummy"><li>
-        <a href="tmp.js.html">tmp.js</a>, <a href="tmp.js.html#line26">line 26</a>
-    </li></ul></dd>
-    
-
-    
-
-    
-
-    
-</dl>
-
-
-
-
-
-
-        
-    
-
-    
         <h3 class="subsection-title">Methods</h3>
 
         
@@ -177,7 +103,9 @@
 
     
 
+    
     <h4 class="name" id="dir"><span class="type-signature"></span>dir<span class="signature">(options, callback<span class="signature-attributes">nullable</span>)</span><span class="type-signature"></span></h4>
+    
 
     
 
@@ -323,7 +251,7 @@
     
     <dt class="tag-source">Source:</dt>
     <dd class="tag-source"><ul class="dummy"><li>
-        <a href="tmp.js.html">tmp.js</a>, <a href="tmp.js.html#line319">line 319</a>
+        <a href="tmp.js.html">tmp.js</a>, <a href="tmp.js.html#line191">line 191</a>
     </li></ul></dd>
     
 
@@ -349,12 +277,18 @@
 
 
 
+
+
+
+
         
             
 
     
 
+    
     <h4 class="name" id="dirSync"><span class="type-signature"></span>dirSync<span class="signature">(options)</span><span class="type-signature"> &rarr; {<a href="global.html#DirSyncObject">DirSyncObject</a>}</span></h4>
+    
 
     
 
@@ -454,7 +388,7 @@
     
     <dt class="tag-source">Source:</dt>
     <dd class="tag-source"><ul class="dummy"><li>
-        <a href="tmp.js.html">tmp.js</a>, <a href="tmp.js.html#line345">line 345</a>
+        <a href="tmp.js.html">tmp.js</a>, <a href="tmp.js.html#line219">line 219</a>
     </li></ul></dd>
     
 
@@ -475,6 +409,8 @@
 
 
 
+
+
 <h5>Throws:</h5>
 
         
@@ -531,12 +467,16 @@
 
 
 
+
+
         
             
 
     
 
+    
     <h4 class="name" id="file"><span class="type-signature"></span>file<span class="signature">(options, callback<span class="signature-attributes">nullable</span>)</span><span class="type-signature"></span></h4>
+    
 
     
 
@@ -590,6 +530,12 @@
 <span class="param-type"><a href="global.html#Options">Options</a></span>
 |
 
+<span class="param-type">null</span>
+|
+
+<span class="param-type">undefined</span>
+|
+
 <span class="param-type"><a href="global.html#fileCallback">fileCallback</a></span>
 
 
@@ -608,7 +554,7 @@
 
             
 
-            <td class="description last">the config options or the callback function</td>
+            <td class="description last">the config options or the callback function or null or undefined</td>
         </tr>
 
     
@@ -682,7 +628,7 @@
     
     <dt class="tag-source">Source:</dt>
     <dd class="tag-source"><ul class="dummy"><li>
-        <a href="tmp.js.html">tmp.js</a>, <a href="tmp.js.html#line211">line 211</a>
+        <a href="tmp.js.html">tmp.js</a>, <a href="tmp.js.html#line126">line 126</a>
     </li></ul></dd>
     
 
@@ -708,12 +654,18 @@
 
 
 
+
+
+
+
         
             
 
     
 
+    
     <h4 class="name" id="fileSync"><span class="type-signature"></span>fileSync<span class="signature">(options)</span><span class="type-signature"> &rarr; {<a href="global.html#FileSyncObject">FileSyncObject</a>}</span></h4>
+    
 
     
 
@@ -813,7 +765,7 @@
     
     <dt class="tag-source">Source:</dt>
     <dd class="tag-source"><ul class="dummy"><li>
-        <a href="tmp.js.html">tmp.js</a>, <a href="tmp.js.html#line259">line 259</a>
+        <a href="tmp.js.html">tmp.js</a>, <a href="tmp.js.html#line164">line 164</a>
     </li></ul></dd>
     
 
@@ -834,6 +786,8 @@
 
 
 
+
+
 <h5>Throws:</h5>
 
         
@@ -890,12 +844,16 @@
 
 
 
+
+
         
             
 
     
 
+    
     <h4 class="name" id="setGracefulCleanup"><span class="type-signature"></span>setGracefulCleanup<span class="signature">()</span><span class="type-signature"></span></h4>
+    
 
     
 
@@ -904,7 +862,9 @@
 <div class="description">
     Sets the graceful cleanup.
 
-Also removes the created files and directories when an uncaught exception occurs.
+If graceful cleanup is set, tmp will remove all controlled temporary objects on process exit, otherwise the
+temporary objects will remain in place, waiting to be cleaned up on system restart or otherwise scheduled temporary
+object removals.
 </div>
 
 
@@ -948,7 +908,7 @@ Also removes the created files and directories when an uncaught exception occurs
     
     <dt class="tag-source">Source:</dt>
     <dd class="tag-source"><ul class="dummy"><li>
-        <a href="tmp.js.html">tmp.js</a>, <a href="tmp.js.html#line465">line 465</a>
+        <a href="tmp.js.html">tmp.js</a>, <a href="tmp.js.html#line630">line 630</a>
     </li></ul></dd>
     
 
@@ -974,12 +934,18 @@ Also removes the created files and directories when an uncaught exception occurs
 
 
 
+
+
+
+
         
             
 
     
 
+    
     <h4 class="name" id="tmpName"><span class="type-signature"></span>tmpName<span class="signature">(options, callback<span class="signature-attributes">nullable</span>)</span><span class="type-signature"></span></h4>
+    
 
     
 
@@ -1125,7 +1091,7 @@ Also removes the created files and directories when an uncaught exception occurs
     
     <dt class="tag-source">Source:</dt>
     <dd class="tag-source"><ul class="dummy"><li>
-        <a href="tmp.js.html">tmp.js</a>, <a href="tmp.js.html#line145">line 145</a>
+        <a href="tmp.js.html">tmp.js</a>, <a href="tmp.js.html#line58">line 58</a>
     </li></ul></dd>
     
 
@@ -1151,12 +1117,18 @@ Also removes the created files and directories when an uncaught exception occurs
 
 
 
+
+
+
+
         
             
 
     
 
+    
     <h4 class="name" id="tmpNameSync"><span class="type-signature"></span>tmpNameSync<span class="signature">(options)</span><span class="type-signature"> &rarr; {string}</span></h4>
+    
 
     
 
@@ -1256,7 +1228,7 @@ Also removes the created files and directories when an uncaught exception occurs
     
     <dt class="tag-source">Source:</dt>
     <dd class="tag-source"><ul class="dummy"><li>
-        <a href="tmp.js.html">tmp.js</a>, <a href="tmp.js.html#line181">line 181</a>
+        <a href="tmp.js.html">tmp.js</a>, <a href="tmp.js.html#line100">line 100</a>
     </li></ul></dd>
     
 
@@ -1277,6 +1249,8 @@ Also removes the created files and directories when an uncaught exception occurs
 
 
 
+
+
 <h5>Throws:</h5>
 
         
@@ -1333,6 +1307,8 @@ Also removes the created files and directories when an uncaught exception occurs
 
 
 
+
+
         
     
 
@@ -1344,7 +1320,9 @@ Also removes the created files and directories when an uncaught exception occurs
 
     
 
+    
     <h4 class="name" id="cleanupCallback"><span class="type-signature"></span>cleanupCallback<span class="signature">(next<span class="signature-attributes">opt</span>)</span><span class="type-signature"></span></h4>
+    
 
     
 
@@ -1415,7 +1393,7 @@ Also removes the created files and directories when an uncaught exception occurs
 
             
 
-            <td class="description last">function to call after entry was removed</td>
+            <td class="description last">function to call whenever the tmp object needs to be removed</td>
         </tr>
 
     
@@ -1456,7 +1434,95 @@ Also removes the created files and directories when an uncaught exception occurs
     
     <dt class="tag-source">Source:</dt>
     <dd class="tag-source"><ul class="dummy"><li>
-        <a href="tmp.js.html">tmp.js</a>, <a href="tmp.js.html#line533">line 533</a>
+        <a href="tmp.js.html">tmp.js</a>, <a href="tmp.js.html#line713">line 713</a>
+    </li></ul></dd>
+    
+
+    
+
+    
+
+    
+</dl>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+            
+                
+
+    
+
+    
+    <h4 class="name" id="cleanupCallbackSync"><span class="type-signature"></span>cleanupCallbackSync<span class="signature">()</span><span class="type-signature"></span></h4>
+    
+
+    
+
+
+
+<div class="description">
+    Removes the temporary created file or directory.
+</div>
+
+
+
+
+
+
+
+
+
+
+
+
+
+<dl class="details">
+
+    
+
+    
+
+    
+
+    
+
+    
+
+    
+
+    
+
+    
+
+    
+
+    
+
+    
+
+    
+
+    
+    <dt class="tag-source">Source:</dt>
+    <dd class="tag-source"><ul class="dummy"><li>
+        <a href="tmp.js.html">tmp.js</a>, <a href="tmp.js.html#line720">line 720</a>
     </li></ul></dd>
     
 
@@ -1482,12 +1548,18 @@ Also removes the created files and directories when an uncaught exception occurs
 
 
 
+
+
+
+
             
                 
 
     
 
+    
     <h4 class="name" id="dirCallback"><span class="type-signature"></span>dirCallback<span class="signature">(err<span class="signature-attributes">nullable</span>, name, fn)</span><span class="type-signature"></span></h4>
+    
 
     
 
@@ -1657,7 +1729,7 @@ Also removes the created files and directories when an uncaught exception occurs
     
     <dt class="tag-source">Source:</dt>
     <dd class="tag-source"><ul class="dummy"><li>
-        <a href="tmp.js.html">tmp.js</a>, <a href="tmp.js.html#line526">line 526</a>
+        <a href="tmp.js.html">tmp.js</a>, <a href="tmp.js.html#line699">line 699</a>
     </li></ul></dd>
     
 
@@ -1683,34 +1755,35 @@ Also removes the created files and directories when an uncaught exception occurs
 
 
 
+
+
+
+
             
                 
-<h4 class="name" id="DirSyncObject">DirSyncObject</h4>
 
+    
 
+    
+    <h4 class="name" id="dirCallbackSync"><span class="type-signature"></span>dirCallbackSync<span class="signature">(err<span class="signature-attributes">nullable</span>, name, fn)</span><span class="type-signature"></span></h4>
+    
 
+    
 
 
 
-    <h5>Type:</h5>
-    <ul>
-        <li>
-            
-<span class="param-type">Object</span>
 
 
-        </li>
-    </ul>
 
 
 
 
 
-    <h5 class="subsection-title">Properties:</h5>
 
+    <h5>Parameters:</h5>
     
 
-<table class="props">
+<table class="params">
     <thead>
     <tr>
         
@@ -1720,6 +1793,8 @@ Also removes the created files and directories when an uncaught exception occurs
         <th>Type</th>
 
         
+        <th>Attributes</th>
+        
 
         
 
@@ -1732,46 +1807,476 @@ Also removes the created files and directories when an uncaught exception occurs
 
         <tr>
             
-                <td class="name"><code>name</code></td>
+                <td class="name"><code>err</code></td>
             
 
             <td class="type">
             
                 
-<span class="param-type">string</span>
+<span class="param-type">Error</span>
 
 
             
             </td>
 
             
+                <td class="attributes">
+                
+
+                
+                    &lt;nullable><br>
+                
+
+                
+                </td>
+            
 
             
 
-            <td class="description last">the name of the directory</td>
+            <td class="description last">the error object if anything goes wrong</td>
         </tr>
 
     
 
         <tr>
             
-                <td class="name"><code>removeCallback</code></td>
+                <td class="name"><code>name</code></td>
             
 
             <td class="type">
             
                 
-<span class="param-type"><a href="global.html#fileCallback">fileCallback</a></span>
+<span class="param-type">string</span>
 
 
             
             </td>
 
             
+                <td class="attributes">
+                
 
-            
+                
 
-            <td class="description last">the callback function to remove the directory</td>
+                
+                </td>
+            
+
+            
+
+            <td class="description last">the temporary file name</td>
+        </tr>
+
+    
+
+        <tr>
+            
+                <td class="name"><code>fn</code></td>
+            
+
+            <td class="type">
+            
+                
+<span class="param-type"><a href="global.html#cleanupCallbackSync">cleanupCallbackSync</a></span>
+
+
+            
+            </td>
+
+            
+                <td class="attributes">
+                
+
+                
+
+                
+                </td>
+            
+
+            
+
+            <td class="description last">the cleanup callback function</td>
+        </tr>
+
+    
+    </tbody>
+</table>
+
+
+
+
+
+
+<dl class="details">
+
+    
+
+    
+
+    
+
+    
+
+    
+
+    
+
+    
+
+    
+
+    
+
+    
+
+    
+
+    
+
+    
+    <dt class="tag-source">Source:</dt>
+    <dd class="tag-source"><ul class="dummy"><li>
+        <a href="tmp.js.html">tmp.js</a>, <a href="tmp.js.html#line706">line 706</a>
+    </li></ul></dd>
+    
+
+    
+
+    
+
+    
+</dl>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+            
+                
+<h4 class="name" id="DirSyncObject">DirSyncObject</h4>
+
+
+
+
+
+
+    <h5>Type:</h5>
+    <ul>
+        <li>
+            
+<span class="param-type">Object</span>
+
+
+        </li>
+    </ul>
+
+
+
+
+
+    <h5 class="subsection-title">Properties:</h5>
+
+    
+
+<table class="props">
+    <thead>
+    <tr>
+        
+        <th>Name</th>
+        
+
+        <th>Type</th>
+
+        
+
+        
+
+        <th class="last">Description</th>
+    </tr>
+    </thead>
+
+    <tbody>
+    
+
+        <tr>
+            
+                <td class="name"><code>name</code></td>
+            
+
+            <td class="type">
+            
+                
+<span class="param-type">string</span>
+
+
+            
+            </td>
+
+            
+
+            
+
+            <td class="description last">the name of the directory</td>
+        </tr>
+
+    
+
+        <tr>
+            
+                <td class="name"><code>removeCallback</code></td>
+            
+
+            <td class="type">
+            
+                
+<span class="param-type"><a href="global.html#fileCallback">fileCallback</a></span>
+
+
+            
+            </td>
+
+            
+
+            
+
+            <td class="description last">the callback function to remove the directory</td>
+        </tr>
+
+    
+    </tbody>
+</table>
+
+
+
+
+<dl class="details">
+
+    
+
+    
+
+    
+
+    
+
+    
+
+    
+
+    
+
+    
+
+    
+
+    
+
+    
+
+    
+
+    
+    <dt class="tag-source">Source:</dt>
+    <dd class="tag-source"><ul class="dummy"><li>
+        <a href="tmp.js.html">tmp.js</a>, <a href="tmp.js.html#line671">line 671</a>
+    </li></ul></dd>
+    
+
+    
+
+    
+
+    
+</dl>
+
+
+
+
+
+
+            
+                
+
+    
+
+    
+    <h4 class="name" id="fileCallback"><span class="type-signature"></span>fileCallback<span class="signature">(err<span class="signature-attributes">nullable</span>, name, fd, fn)</span><span class="type-signature"></span></h4>
+    
+
+    
+
+
+
+
+
+
+
+
+
+
+
+    <h5>Parameters:</h5>
+    
+
+<table class="params">
+    <thead>
+    <tr>
+        
+        <th>Name</th>
+        
+
+        <th>Type</th>
+
+        
+        <th>Attributes</th>
+        
+
+        
+
+        <th class="last">Description</th>
+    </tr>
+    </thead>
+
+    <tbody>
+    
+
+        <tr>
+            
+                <td class="name"><code>err</code></td>
+            
+
+            <td class="type">
+            
+                
+<span class="param-type">Error</span>
+
+
+            
+            </td>
+
+            
+                <td class="attributes">
+                
+
+                
+                    &lt;nullable><br>
+                
+
+                
+                </td>
+            
+
+            
+
+            <td class="description last">the error object if anything goes wrong</td>
+        </tr>
+
+    
+
+        <tr>
+            
+                <td class="name"><code>name</code></td>
+            
+
+            <td class="type">
+            
+                
+<span class="param-type">string</span>
+
+
+            
+            </td>
+
+            
+                <td class="attributes">
+                
+
+                
+
+                
+                </td>
+            
+
+            
+
+            <td class="description last">the temporary file name</td>
+        </tr>
+
+    
+
+        <tr>
+            
+                <td class="name"><code>fd</code></td>
+            
+
+            <td class="type">
+            
+                
+<span class="param-type">number</span>
+
+
+            
+            </td>
+
+            
+                <td class="attributes">
+                
+
+                
+
+                
+                </td>
+            
+
+            
+
+            <td class="description last">the file descriptor or -1 if the fd had been discarded</td>
+        </tr>
+
+    
+
+        <tr>
+            
+                <td class="name"><code>fn</code></td>
+            
+
+            <td class="type">
+            
+                
+<span class="param-type"><a href="global.html#cleanupCallback">cleanupCallback</a></span>
+
+
+            
+            </td>
+
+            
+                <td class="attributes">
+                
+
+                
+
+                
+                </td>
+            
+
+            
+
+            <td class="description last">the cleanup callback function</td>
         </tr>
 
     
@@ -1781,6 +2286,8 @@ Also removes the created files and directories when an uncaught exception occurs
 
 
 
+
+
 <dl class="details">
 
     
@@ -1810,7 +2317,7 @@ Also removes the created files and directories when an uncaught exception occurs
     
     <dt class="tag-source">Source:</dt>
     <dd class="tag-source"><ul class="dummy"><li>
-        <a href="tmp.js.html">tmp.js</a>, <a href="tmp.js.html#line506">line 506</a>
+        <a href="tmp.js.html">tmp.js</a>, <a href="tmp.js.html#line683">line 683</a>
     </li></ul></dd>
     
 
@@ -1825,13 +2332,29 @@ Also removes the created files and directories when an uncaught exception occurs
 
 
 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
 
             
                 
 
     
 
-    <h4 class="name" id="fileCallback"><span class="type-signature"></span>fileCallback<span class="signature">(err<span class="signature-attributes">nullable</span>, name, fd, fn)</span><span class="type-signature"></span></h4>
+    
+    <h4 class="name" id="fileCallbackSync"><span class="type-signature"></span>fileCallbackSync<span class="signature">(err<span class="signature-attributes">nullable</span>, name, fd, fn)</span><span class="type-signature"></span></h4>
+    
 
     
 
@@ -1960,7 +2483,7 @@ Also removes the created files and directories when an uncaught exception occurs
 
             
 
-            <td class="description last">the file descriptor</td>
+            <td class="description last">the file descriptor or -1 if the fd had been discarded</td>
         </tr>
 
     
@@ -1973,7 +2496,7 @@ Also removes the created files and directories when an uncaught exception occurs
             <td class="type">
             
                 
-<span class="param-type"><a href="global.html#cleanupCallback">cleanupCallback</a></span>
+<span class="param-type"><a href="global.html#cleanupCallbackSync">cleanupCallbackSync</a></span>
 
 
             
@@ -2032,7 +2555,7 @@ Also removes the created files and directories when an uncaught exception occurs
     
     <dt class="tag-source">Source:</dt>
     <dd class="tag-source"><ul class="dummy"><li>
-        <a href="tmp.js.html">tmp.js</a>, <a href="tmp.js.html#line518">line 518</a>
+        <a href="tmp.js.html">tmp.js</a>, <a href="tmp.js.html#line691">line 691</a>
     </li></ul></dd>
     
 
@@ -2058,6 +2581,10 @@ Also removes the created files and directories when an uncaught exception occurs
 
 
 
+
+
+
+
             
                 
 <h4 class="name" id="FileSyncObject">FileSyncObject</h4>
@@ -2146,7 +2673,7 @@ Also removes the created files and directories when an uncaught exception occurs
 
             
 
-            <td class="description last">the file descriptor</td>
+            <td class="description last">the file descriptor or -1 if the fd has been discarded</td>
         </tr>
 
     
@@ -2208,7 +2735,7 @@ Also removes the created files and directories when an uncaught exception occurs
     
     <dt class="tag-source">Source:</dt>
     <dd class="tag-source"><ul class="dummy"><li>
-        <a href="tmp.js.html">tmp.js</a>, <a href="tmp.js.html#line499">line 499</a>
+        <a href="tmp.js.html">tmp.js</a>, <a href="tmp.js.html#line664">line 664</a>
     </li></ul></dd>
     
 
@@ -2277,6 +2804,37 @@ Also removes the created files and directories when an uncaught exception occurs
     <tbody>
     
 
+        <tr>
+            
+                <td class="name"><code>keep</code></td>
+            
+
+            <td class="type">
+            
+                
+<span class="param-type">boolean</span>
+
+
+            
+            </td>
+
+            
+                <td class="attributes">
+                
+
+                
+                    &lt;nullable><br>
+                
+                </td>
+            
+
+            
+
+            <td class="description last">the temporary object (file or dir) will not be garbage collected</td>
+        </tr>
+
+    
+
         <tr>
             
                 <td class="name"><code>tries</code></td>
@@ -2308,6 +2866,30 @@ Also removes the created files and directories when an uncaught exception occurs
 
     
 
+        <tr>
+            
+                <td class="name"><code>(?int)</code></td>
+            
+
+            <td class="type">
+            
+            </td>
+
+            
+                <td class="attributes">
+                
+
+                
+                </td>
+            
+
+            
+
+            <td class="description last">mode the access mode, defaults are 0o700 for directories and 0o600 for files</td>
+        </tr>
+
+    
+
         <tr>
             
                 <td class="name"><code>template</code></td>
@@ -2365,7 +2947,7 @@ Also removes the created files and directories when an uncaught exception occurs
 
             
 
-            <td class="description last">fix name</td>
+            <td class="description last">fixed name relative to tmpdir or the specified dir option</td>
         </tr>
 
     
@@ -2396,7 +2978,7 @@ Also removes the created files and directories when an uncaught exception occurs
 
             
 
-            <td class="description last">the tmp directory to use</td>
+            <td class="description last">tmp directory relative to the system tmp directory to use</td>
         </tr>
 
     
@@ -2462,6 +3044,99 @@ Also removes the created files and directories when an uncaught exception occurs
         </tr>
 
     
+
+        <tr>
+            
+                <td class="name"><code>unsafeCleanup</code></td>
+            
+
+            <td class="type">
+            
+                
+<span class="param-type">boolean</span>
+
+
+            
+            </td>
+
+            
+                <td class="attributes">
+                
+
+                
+                    &lt;nullable><br>
+                
+                </td>
+            
+
+            
+
+            <td class="description last">recursively removes the created temporary directory, even when it's not empty</td>
+        </tr>
+
+    
+
+        <tr>
+            
+                <td class="name"><code>detachDescriptor</code></td>
+            
+
+            <td class="type">
+            
+                
+<span class="param-type">boolean</span>
+
+
+            
+            </td>
+
+            
+                <td class="attributes">
+                
+
+                
+                    &lt;nullable><br>
+                
+                </td>
+            
+
+            
+
+            <td class="description last">detaches the file descriptor, caller is responsible for closing the file, tmp will no longer try closing the file during garbage collection</td>
+        </tr>
+
+    
+
+        <tr>
+            
+                <td class="name"><code>discardDescriptor</code></td>
+            
+
+            <td class="type">
+            
+                
+<span class="param-type">boolean</span>
+
+
+            
+            </td>
+
+            
+                <td class="attributes">
+                
+
+                
+                    &lt;nullable><br>
+                
+                </td>
+            
+
+            
+
+            <td class="description last">discards the file descriptor (closes file, fd is -1), tmp will no longer try closing the file during garbage collection</td>
+        </tr>
+
+    
     </tbody>
 </table>
 
@@ -2497,7 +3172,7 @@ Also removes the created files and directories when an uncaught exception occurs
     
     <dt class="tag-source">Source:</dt>
     <dd class="tag-source"><ul class="dummy"><li>
-        <a href="tmp.js.html">tmp.js</a>, <a href="tmp.js.html#line487">line 487</a>
+        <a href="tmp.js.html">tmp.js</a>, <a href="tmp.js.html#line647">line 647</a>
     </li></ul></dd>
     
 
@@ -2518,7 +3193,9 @@ Also removes the created files and directories when an uncaught exception occurs
 
     
 
+    
     <h4 class="name" id="simpleCallback"><span class="type-signature"></span>simpleCallback<span class="signature">()</span><span class="type-signature"></span></h4>
+    
 
     
 
@@ -2569,7 +3246,7 @@ Also removes the created files and directories when an uncaught exception occurs
     
     <dt class="tag-source">Source:</dt>
     <dd class="tag-source"><ul class="dummy"><li>
-        <a href="tmp.js.html">tmp.js</a>, <a href="tmp.js.html#line540">line 540</a>
+        <a href="tmp.js.html">tmp.js</a>, <a href="tmp.js.html#line726">line 726</a>
     </li></ul></dd>
     
 
@@ -2602,12 +3279,18 @@ Also removes the created files and directories when an uncaught exception occurs
 
 
 
+
+
+
+
             
                 
 
     
 
+    
     <h4 class="name" id="tmpNameCallback"><span class="type-signature"></span>tmpNameCallback<span class="signature">(err<span class="signature-attributes">nullable</span>, name)</span><span class="type-signature"></span></h4>
+    
 
     
 
@@ -2746,7 +3429,7 @@ Also removes the created files and directories when an uncaught exception occurs
     
     <dt class="tag-source">Source:</dt>
     <dd class="tag-source"><ul class="dummy"><li>
-        <a href="tmp.js.html">tmp.js</a>, <a href="tmp.js.html#line512">line 512</a>
+        <a href="tmp.js.html">tmp.js</a>, <a href="tmp.js.html#line677">line 677</a>
     </li></ul></dd>
     
 
@@ -2772,6 +3455,10 @@ Also removes the created files and directories when an uncaught exception occurs
 
 
 
+
+
+
+
             
     
 
@@ -2786,13 +3473,13 @@ Also removes the created files and directories when an uncaught exception occurs
 </div>
 
 <nav>
-    <h2><a href="index.html">Home</a></h2><h3>Global</h3><ul><li><a href="global.html#dir">dir</a></li><li><a href="global.html#dirSync">dirSync</a></li><li><a href="global.html#file">file</a></li><li><a href="global.html#fileSync">fileSync</a></li><li><a href="global.html#setGracefulCleanup">setGracefulCleanup</a></li><li><a href="global.html#tmpDir">tmpDir</a></li><li><a href="global.html#tmpName">tmpName</a></li><li><a href="global.html#tmpNameSync">tmpNameSync</a></li></ul>
+    <h2><a href="index.html">Home</a></h2><h3>Global</h3><ul><li><a href="global.html#dir">dir</a></li><li><a href="global.html#dirSync">dirSync</a></li><li><a href="global.html#file">file</a></li><li><a href="global.html#fileSync">fileSync</a></li><li><a href="global.html#setGracefulCleanup">setGracefulCleanup</a></li><li><a href="global.html#tmpName">tmpName</a></li><li><a href="global.html#tmpNameSync">tmpNameSync</a></li></ul>
 </nav>
 
 <br class="clear">
 
 <footer>
-    Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.4.3</a> on Sat Nov 26 2016 21:53:28 GMT+0100 (CET)
+    Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.3</a> on Sat Feb 08 2020 01:04:48 GMT+0100 (GMT+01:00)
 </footer>
 
 <script> prettyPrint(); </script>
diff --git a/docs/index.html b/docs/index.html
index cb4de81..2748241 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -43,94 +43,144 @@
 
 
     <section>
-        <article><h1>Tmp</h1><p>A simple temporary file and directory creator for <a href="http://nodejs.org/">node.js.</a></p>
+        <article><h1>Tmp</h1>
+<p>A simple temporary file and directory creator for <a href="http://nodejs.org/">node.js.</a></p>
 <p><a href="https://travis-ci.org/raszi/node-tmp"><img src="https://travis-ci.org/raszi/node-tmp.svg?branch=master" alt="Build Status"></a>
 <a href="https://david-dm.org/raszi/node-tmp"><img src="https://david-dm.org/raszi/node-tmp.svg" alt="Dependencies"></a>
 <a href="https://badge.fury.io/js/tmp"><img src="https://badge.fury.io/js/tmp.svg" alt="npm version"></a>
+<a href="https://raszi.github.io/node-tmp/"><img src="https://img.shields.io/badge/API-documented-brightgreen.svg" alt="API documented"></a>
 <a href="https://snyk.io/test/npm/tmp"><img src="https://snyk.io/test/npm/tmp/badge.svg" alt="Known Vulnerabilities"></a></p>
-<h2>About</h2><p>This is a <a href="https://www.npmjs.com/browse/depended/tmp">widely used library</a> to create temporary files and directories
+<h2>About</h2>
+<p>This is a <a href="https://www.npmjs.com/browse/depended/tmp">widely used library</a> to create temporary files and directories
 in a <a href="http://nodejs.org/">node.js</a> environment.</p>
 <p>Tmp offers both an asynchronous and a synchronous API. For all API calls, all
-the parameters are optional.</p>
+the parameters are optional. There also exists a promisified version of the
+API, see <a href="https://github.com/benjamingr/tmp-promise">tmp-promise</a>.</p>
 <p>Tmp uses crypto for determining random file names, or, when using templates,
 a six letter random identifier. And just in case that you do not have that much
 entropy left on your system, Tmp will fall back to pseudo random numbers.</p>
 <p>You can set whether you want to remove the temporary file on process exit or
-not, and the destination directory can also be set.</p>
-<h2>How to install</h2><pre class="prettyprint source lang-bash"><code>npm install tmp</code></pre><h2>Usage</h2><h3>Asynchronous file creation</h3><p>Simple temporary file creation, the file will be closed and unlinked on process exit.</p>
-<pre class="prettyprint source lang-javascript"><code>var tmp = require('tmp');
+not.</p>
+<p>If you do not want to store your temporary directories and files in the
+standard OS temporary directory, then you are free to override that as well.</p>
+<h2>An Important Note on Compatibility</h2>
+<p>See the <a href="./CHANGELOG.md">CHANGELOG</a> for more information.</p>
+<h3>Version 0.1.0</h3>
+<p>Since version 0.1.0, all support for node versions &lt; 0.10.0 has been dropped.</p>
+<p>Most importantly, any support for earlier versions of node-tmp was also dropped.</p>
+<p>If you still require node versions &lt; 0.10.0, then you must limit your node-tmp
+dependency to versions below 0.1.0.</p>
+<h3>Version 0.0.33</h3>
+<p>Since version 0.0.33, all support for node versions &lt; 0.8 has been dropped.</p>
+<p>If you still require node version 0.8, then you must limit your node-tmp
+dependency to version 0.0.33.</p>
+<p>For node versions &lt; 0.8 you must limit your node-tmp dependency to
+versions &lt; 0.0.33.</p>
+<h2>How to install</h2>
+<pre class="prettyprint source lang-bash"><code>npm install tmp
+</code></pre>
+<h2>Usage</h2>
+<p>Please also check <a href="https://raszi.github.io/node-tmp/">API docs</a>.</p>
+<h3>Asynchronous file creation</h3>
+<p>Simple temporary file creation, the file will be closed and unlinked on process exit.</p>
+<pre class="prettyprint source lang-javascript"><code>const tmp = require('tmp');
 
 tmp.file(function _tempFileCreated(err, path, fd, cleanupCallback) {
   if (err) throw err;
 
-  console.log(&quot;File: &quot;, path);
-  console.log(&quot;Filedescriptor: &quot;, fd);
-
+  console.log('File: ', path);
+  console.log('Filedescriptor: ', fd);
+  
   // If we don't need the file anymore we could manually call the cleanupCallback
   // But that is not necessary if we didn't pass the keep option because the library
   // will clean after itself.
   cleanupCallback();
-});</code></pre><h3>Synchronous file creation</h3><p>A synchronous version of the above.</p>
-<pre class="prettyprint source lang-javascript"><code>var tmp = require('tmp');
-
-var tmpobj = tmp.fileSync();
-console.log(&quot;File: &quot;, tmpobj.name);
-console.log(&quot;Filedescriptor: &quot;, tmpobj.fd);
-
+});
+</code></pre>
+<h3>Synchronous file creation</h3>
+<p>A synchronous version of the above.</p>
+<pre class="prettyprint source lang-javascript"><code>const tmp = require('tmp');
+
+const tmpobj = tmp.fileSync();
+console.log('File: ', tmpobj.name);
+console.log('Filedescriptor: ', tmpobj.fd);
+  
 // If we don't need the file anymore we could manually call the removeCallback
 // But that is not necessary if we didn't pass the keep option because the library
 // will clean after itself.
-tmpobj.removeCallback();</code></pre><p>Note that this might throw an exception if either the maximum limit of retries
+tmpobj.removeCallback();
+</code></pre>
+<p>Note that this might throw an exception if either the maximum limit of retries
 for creating a temporary name fails, or, in case that you do not have the permission
 to write to the directory where the temporary file should be created in.</p>
-<h3>Asynchronous directory creation</h3><p>Simple temporary directory creation, it will be removed on process exit.</p>
+<h3>Asynchronous directory creation</h3>
+<p>Simple temporary directory creation, it will be removed on process exit.</p>
 <p>If the directory still contains items on process exit, then it won't be removed.</p>
-<pre class="prettyprint source lang-javascript"><code>var tmp = require('tmp');
+<pre class="prettyprint source lang-javascript"><code>const tmp = require('tmp');
 
 tmp.dir(function _tempDirCreated(err, path, cleanupCallback) {
   if (err) throw err;
 
-  console.log(&quot;Dir: &quot;, path);
-
+  console.log('Dir: ', path);
+  
   // Manual cleanup
   cleanupCallback();
-});</code></pre><p>If you want to cleanup the directory even when there are entries in it, then
+});
+</code></pre>
+<p>If you want to cleanup the directory even when there are entries in it, then
 you can pass the <code>unsafeCleanup</code> option when creating it.</p>
-<h3>Synchronous directory creation</h3><p>A synchronous version of the above.</p>
-<pre class="prettyprint source lang-javascript"><code>var tmp = require('tmp');
+<h3>Synchronous directory creation</h3>
+<p>A synchronous version of the above.</p>
+<pre class="prettyprint source lang-javascript"><code>const tmp = require('tmp');
 
-var tmpobj = tmp.dirSync();
-console.log(&quot;Dir: &quot;, tmpobj.name);
+const tmpobj = tmp.dirSync();
+console.log('Dir: ', tmpobj.name);
 // Manual cleanup
-tmpobj.removeCallback();</code></pre><p>Note that this might throw an exception if either the maximum limit of retries
+tmpobj.removeCallback();
+</code></pre>
+<p>Note that this might throw an exception if either the maximum limit of retries
 for creating a temporary name fails, or, in case that you do not have the permission
 to write to the directory where the temporary directory should be created in.</p>
-<h3>Asynchronous filename generation</h3><p>It is possible with this library to generate a unique filename in the specified
+<h3>Asynchronous filename generation</h3>
+<p>It is possible with this library to generate a unique filename in the specified
 directory.</p>
-<pre class="prettyprint source lang-javascript"><code>var tmp = require('tmp');
+<pre class="prettyprint source lang-javascript"><code>const tmp = require('tmp');
 
 tmp.tmpName(function _tempNameGenerated(err, path) {
     if (err) throw err;
 
-    console.log(&quot;Created temporary filename: &quot;, path);
-});</code></pre><h3>Synchronous filename generation</h3><p>A synchronous version of the above.</p>
-<pre class="prettyprint source lang-javascript"><code>var tmp = require('tmp');
-
-var name = tmp.tmpNameSync();
-console.log(&quot;Created temporary filename: &quot;, name);</code></pre><h2>Advanced usage</h2><h3>Asynchronous file creation</h3><p>Creates a file with mode <code>0644</code>, prefix will be <code>prefix-</code> and postfix will be <code>.txt</code>.</p>
-<pre class="prettyprint source lang-javascript"><code>var tmp = require('tmp');
-
-tmp.file({ mode: 0644, prefix: 'prefix-', postfix: '.txt' }, function _tempFileCreated(err, path, fd) {
+    console.log('Created temporary filename: ', path);
+});
+</code></pre>
+<h3>Synchronous filename generation</h3>
+<p>A synchronous version of the above.</p>
+<pre class="prettyprint source lang-javascript"><code>const tmp = require('tmp');
+
+const name = tmp.tmpNameSync();
+console.log('Created temporary filename: ', name);
+</code></pre>
+<h2>Advanced usage</h2>
+<h3>Asynchronous file creation</h3>
+<p>Creates a file with mode <code>0644</code>, prefix will be <code>prefix-</code> and postfix will be <code>.txt</code>.</p>
+<pre class="prettyprint source lang-javascript"><code>const tmp = require('tmp');
+
+tmp.file({ mode: 0o644, prefix: 'prefix-', postfix: '.txt' }, function _tempFileCreated(err, path, fd) {
   if (err) throw err;
 
-  console.log(&quot;File: &quot;, path);
-  console.log(&quot;Filedescriptor: &quot;, fd);
-});</code></pre><h3>Synchronous file creation</h3><p>A synchronous version of the above.</p>
-<pre class="prettyprint source lang-javascript"><code>var tmp = require('tmp');
-
-var tmpobj = tmp.fileSync({ mode: 0644, prefix: 'prefix-', postfix: '.txt' });
-console.log(&quot;File: &quot;, tmpobj.name);
-console.log(&quot;Filedescriptor: &quot;, tmpobj.fd);</code></pre><h3>Controlling the Descriptor</h3><p>As a side effect of creating a unique file <code>tmp</code> gets a file descriptor that is
+  console.log('File: ', path);
+  console.log('Filedescriptor: ', fd);
+});
+</code></pre>
+<h3>Synchronous file creation</h3>
+<p>A synchronous version of the above.</p>
+<pre class="prettyprint source lang-javascript"><code>const tmp = require('tmp');
+
+const tmpobj = tmp.fileSync({ mode: 0o644, prefix: 'prefix-', postfix: '.txt' });
+console.log('File: ', tmpobj.name);
+console.log('Filedescriptor: ', tmpobj.fd);
+</code></pre>
+<h3>Controlling the Descriptor</h3>
+<p>As a side effect of creating a unique file <code>tmp</code> gets a file descriptor that is
 returned to the user as the <code>fd</code> parameter.  The descriptor may be used by the
 application and is closed when the <code>removeCallback</code> is invoked.</p>
 <p>In some use cases the application does not need the descriptor, needs to close it
@@ -143,13 +193,15 @@ is created.  In this case the <code>fd</code> parameter is undefined.</li>
 parameter, but it is the application's responsibility to close it when it is no
 longer needed.</li>
 </ul>
-<pre class="prettyprint source lang-javascript"><code>var tmp = require('tmp');
+<pre class="prettyprint source lang-javascript"><code>const tmp = require('tmp');
 
 tmp.file({ discardDescriptor: true }, function _tempFileCreated(err, path, fd, cleanupCallback) {
   if (err) throw err;
   // fd will be undefined, allowing application to use fs.createReadStream(path)
   // without holding an unused descriptor open.
-});</code></pre><pre class="prettyprint source lang-javascript"><code>var tmp = require('tmp');
+});
+</code></pre>
+<pre class="prettyprint source lang-javascript"><code>const tmp = require('tmp');
 
 tmp.file({ detachDescriptor: true }, function _tempFileCreated(err, path, fd, cleanupCallback) {
   if (err) throw err;
@@ -158,55 +210,101 @@ tmp.file({ detachDescriptor: true }, function _tempFileCreated(err, path, fd, cl
   // Application can store data through fd here; the space used will automatically
   // be reclaimed by the operating system when the descriptor is closed or program
   // terminates.
-});</code></pre><h3>Asynchronous directory creation</h3><p>Creates a directory with mode <code>0755</code>, prefix will be <code>myTmpDir_</code>.</p>
-<pre class="prettyprint source lang-javascript"><code>var tmp = require('tmp');
+});
+</code></pre>
+<h3>Asynchronous directory creation</h3>
+<p>Creates a directory with mode <code>0755</code>, prefix will be <code>myTmpDir_</code>.</p>
+<pre class="prettyprint source lang-javascript"><code>const tmp = require('tmp');
 
-tmp.dir({ mode: 0750, prefix: 'myTmpDir_' }, function _tempDirCreated(err, path) {
+tmp.dir({ mode: 0o750, prefix: 'myTmpDir_' }, function _tempDirCreated(err, path) {
   if (err) throw err;
 
-  console.log(&quot;Dir: &quot;, path);
-});</code></pre><h3>Synchronous directory creation</h3><p>Again, a synchronous version of the above.</p>
-<pre class="prettyprint source lang-javascript"><code>var tmp = require('tmp');
-
-var tmpobj = tmp.dirSync({ mode: 0750, prefix: 'myTmpDir_' });
-console.log(&quot;Dir: &quot;, tmpobj.name);</code></pre><h3>mkstemp like, asynchronously</h3><p>Creates a new temporary directory with mode <code>0700</code> and filename like <code>/tmp/tmp-nk2J1u</code>.</p>
-<pre class="prettyprint source lang-javascript"><code>var tmp = require('tmp');
-
-tmp.dir({ template: '/tmp/tmp-XXXXXX' }, function _tempDirCreated(err, path) {
+  console.log('Dir: ', path);
+});
+</code></pre>
+<h3>Synchronous directory creation</h3>
+<p>Again, a synchronous version of the above.</p>
+<pre class="prettyprint source lang-javascript"><code>const tmp = require('tmp');
+
+const tmpobj = tmp.dirSync({ mode: 0750, prefix: 'myTmpDir_' });
+console.log('Dir: ', tmpobj.name);
+</code></pre>
+<h3>mkstemp like, asynchronously</h3>
+<p>Creates a new temporary directory with mode <code>0700</code> and filename like <code>/tmp/tmp-nk2J1u</code>.</p>
+<p>IMPORTANT NOTE: template no longer accepts a path. Use the dir option instead if you
+require tmp to create your temporary filesystem object in a different place than the
+default <code>tmp.tmpdir</code>.</p>
+<pre class="prettyprint source lang-javascript"><code>const tmp = require('tmp');
+
+tmp.dir({ template: 'tmp-XXXXXX' }, function _tempDirCreated(err, path) {
   if (err) throw err;
 
-  console.log(&quot;Dir: &quot;, path);
-});</code></pre><h3>mkstemp like, synchronously</h3><p>This will behave similarly to the asynchronous version.</p>
-<pre class="prettyprint source lang-javascript"><code>var tmp = require('tmp');
-
-var tmpobj = tmp.dirSync({ template: '/tmp/tmp-XXXXXX' });
-console.log(&quot;Dir: &quot;, tmpobj.name);</code></pre><h3>Asynchronous filename generation</h3><p>The <code>tmpName()</code> function accepts the <code>prefix</code>, <code>postfix</code>, <code>dir</code>, etc. parameters also:</p>
-<pre class="prettyprint source lang-javascript"><code>var tmp = require('tmp');
-
-tmp.tmpName({ template: '/tmp/tmp-XXXXXX' }, function _tempNameGenerated(err, path) {
+  console.log('Dir: ', path);
+});
+</code></pre>
+<h3>mkstemp like, synchronously</h3>
+<p>This will behave similarly to the asynchronous version.</p>
+<pre class="prettyprint source lang-javascript"><code>const tmp = require('tmp');
+
+const tmpobj = tmp.dirSync({ template: 'tmp-XXXXXX' });
+console.log('Dir: ', tmpobj.name);
+</code></pre>
+<h3>Asynchronous filename generation</h3>
+<p>Using <code>tmpName()</code> you can create temporary file names asynchronously.
+The function accepts all standard options, e.g. <code>prefix</code>, <code>postfix</code>, <code>dir</code>, and so on.</p>
+<p>You can also leave out the options altogether and just call the function with a callback as first parameter.</p>
+<pre class="prettyprint source lang-javascript"><code>const tmp = require('tmp');
+
+const options = {};
+
+tmp.tmpName(options, function _tempNameGenerated(err, path) {
     if (err) throw err;
 
-    console.log(&quot;Created temporary filename: &quot;, path);
-});</code></pre><h3>Synchronous filename generation</h3><p>The <code>tmpNameSync()</code> function works similarly to <code>tmpName()</code>.</p>
-<pre class="prettyprint source lang-javascript"><code>var tmp = require('tmp');
-var tmpname = tmp.tmpNameSync({ template: '/tmp/tmp-XXXXXX' });
-console.log(&quot;Created temporary filename: &quot;, tmpname);</code></pre><h2>Graceful cleanup</h2><p>One may want to cleanup the temporary files even when an uncaught exception
-occurs. To enforce this, you can call the <code>setGracefulCleanup()</code> method:</p>
-<pre class="prettyprint source lang-javascript"><code>var tmp = require('tmp');
-
-tmp.setGracefulCleanup();</code></pre><h2>Options</h2><p>All options are optional :)</p>
+    console.log('Created temporary filename: ', path);
+});
+</code></pre>
+<h3>Synchronous filename generation</h3>
+<p>The <code>tmpNameSync()</code> function works similarly to <code>tmpName()</code>.
+Again, you can leave out the options altogether and just invoke the function without any parameters.</p>
+<pre class="prettyprint source lang-javascript"><code>const tmp = require('tmp');
+const options = {};
+const tmpname = tmp.tmpNameSync(options);
+console.log('Created temporary filename: ', tmpname);
+</code></pre>
+<h2>Graceful cleanup</h2>
+<p>If graceful cleanup is set, tmp will remove all controlled temporary objects on process exit, otherwise the
+temporary objects will remain in place, waiting to be cleaned up on system restart or otherwise scheduled temporary
+object removal.</p>
+<p>To enforce this, you can call the <code>setGracefulCleanup()</code> method:</p>
+<pre class="prettyprint source lang-javascript"><code>const tmp = require('tmp');
+
+tmp.setGracefulCleanup();
+</code></pre>
+<h2>Options</h2>
+<p>All options are optional :)</p>
 <ul>
-<li><code>mode</code>: the file mode to create with, it fallbacks to <code>0600</code> on file creation and <code>0700</code> on directory creation</li>
-<li><code>prefix</code>: the optional prefix, fallbacks to <code>tmp-</code> if not provided</li>
-<li><code>postfix</code>: the optional postfix, fallbacks to <code>.tmp</code> on file creation</li>
-<li><code>template</code>: <a href="http://www.kernel.org/doc/man-pages/online/pages/man3/mkstemp.3.html"><code>mkstemp</code></a> like filename template, no default</li>
-<li><code>dir</code>: the optional temporary directory, fallbacks to system default (guesses from environment)</li>
+<li><code>name</code>: a fixed name that overrides random name generation, the name must be relative and must not contain path segments</li>
+<li><code>mode</code>: the file mode to create with, falls back to <code>0o600</code> on file creation and <code>0o700</code> on directory creation</li>
+<li><code>prefix</code>: the optional prefix, defaults to <code>tmp</code></li>
+<li><code>postfix</code>: the optional postfix</li>
+<li><code>template</code>: <a href="http://www.kernel.org/doc/man-pages/online/pages/man3/mkstemp.3.html"><code>mkstemp</code></a> like filename template, no default, can be either an absolute or a relative path that resolves
+to a relative path of the system's default temporary directory, must include <code>XXXXXX</code> once for random name generation, e.g.
+'foo/bar/XXXXXX'. Absolute paths are also fine as long as they are relative to os.tmpdir().
+Any directories along the so specified path must exist, otherwise a ENOENT error will be thrown upon access,
+as tmp will not check the availability of the path, nor will it establish the requested path for you.</li>
+<li><code>dir</code>: the optional temporary directory that must be relative to the system's default temporary directory.
+absolute paths are fine as long as they point to a location under the system's default temporary directory.
+Any directories along the so specified path must exist, otherwise a ENOENT error will be thrown upon access,
+as tmp will not check the availability of the path, nor will it establish the requested path for you.</li>
 <li><code>tries</code>: how many times should the function try to get a unique filename before giving up, default <code>3</code></li>
-<li><code>keep</code>: signals that the temporary file or directory should not be deleted on exit, default is <code>false</code>, means delete<ul>
-<li>Please keep in mind that it is recommended in this case to call the provided <code>cleanupCallback</code> function manually.</li>
+<li><code>keep</code>: signals that the temporary file or directory should not be deleted on exit, default is <code>false</code>
+<ul>
+<li>In order to clean up, you will have to call the provided <code>cleanupCallback</code> function manually.</li>
 </ul>
 </li>
 <li><code>unsafeCleanup</code>: recursively removes the created temporary directory, even when it's not empty. default is <code>false</code></li>
+<li><code>detachDescriptor</code>: detaches the file descriptor, caller is responsible for closing the file, tmp will no longer try closing the file during garbage collection</li>
+<li><code>discardDescriptor</code>: discards the file descriptor (closes file, fd is -1), tmp will no longer try closing the file during garbage collection</li>
 </ul></article>
     </section>
 
@@ -218,13 +316,13 @@ tmp.setGracefulCleanup();</code></pre><h2>Options</h2><p>All options are optiona
 </div>
 
 <nav>
-    <h2><a href="index.html">Home</a></h2><h3>Global</h3><ul><li><a href="global.html#dir">dir</a></li><li><a href="global.html#dirSync">dirSync</a></li><li><a href="global.html#file">file</a></li><li><a href="global.html#fileSync">fileSync</a></li><li><a href="global.html#setGracefulCleanup">setGracefulCleanup</a></li><li><a href="global.html#tmpDir">tmpDir</a></li><li><a href="global.html#tmpName">tmpName</a></li><li><a href="global.html#tmpNameSync">tmpNameSync</a></li></ul>
+    <h2><a href="index.html">Home</a></h2><h3>Global</h3><ul><li><a href="global.html#dir">dir</a></li><li><a href="global.html#dirSync">dirSync</a></li><li><a href="global.html#file">file</a></li><li><a href="global.html#fileSync">fileSync</a></li><li><a href="global.html#setGracefulCleanup">setGracefulCleanup</a></li><li><a href="global.html#tmpName">tmpName</a></li><li><a href="global.html#tmpNameSync">tmpNameSync</a></li></ul>
 </nav>
 
 <br class="clear">
 
 <footer>
-    Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.4.3</a> on Sat Nov 26 2016 21:53:28 GMT+0100 (CET)
+    Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.3</a> on Sat Feb 08 2020 01:04:48 GMT+0100 (GMT+01:00)
 </footer>
 
 <script> prettyPrint(); </script>
diff --git a/docs/scripts/linenumber.js b/docs/scripts/linenumber.js
index 8d52f7e..4354785 100644
--- a/docs/scripts/linenumber.js
+++ b/docs/scripts/linenumber.js
@@ -1,12 +1,12 @@
 /*global document */
-(function() {
-    var source = document.getElementsByClassName('prettyprint source linenums');
-    var i = 0;
-    var lineNumber = 0;
-    var lineId;
-    var lines;
-    var totalLines;
-    var anchorHash;
+(() => {
+    const source = document.getElementsByClassName('prettyprint source linenums');
+    let i = 0;
+    let lineNumber = 0;
+    let lineId;
+    let lines;
+    let totalLines;
+    let anchorHash;
 
     if (source && source[0]) {
         anchorHash = document.location.hash.substring(1);
@@ -15,7 +15,7 @@
 
         for (; i < totalLines; i++) {
             lineNumber++;
-            lineId = 'line' + lineNumber;
+            lineId = `line${lineNumber}`;
             lines[i].id = lineId;
             if (lineId === anchorHash) {
                 lines[i].className += ' selected';
diff --git a/docs/styles/jsdoc-default.css b/docs/styles/jsdoc-default.css
index ede1919..7d1729d 100644
--- a/docs/styles/jsdoc-default.css
+++ b/docs/styles/jsdoc-default.css
@@ -78,6 +78,10 @@ article dl {
     margin-bottom: 40px;
 }
 
+article img {
+  max-width: 100%;
+}
+
 section
 {
     display: block;
@@ -218,8 +222,8 @@ thead tr
 th { border-right: 1px solid #aaa; }
 tr > th:last-child { border-right: 1px solid #ddd; }
 
-.ancestors { color: #999; }
-.ancestors a
+.ancestors, .attribs { color: #999; }
+.ancestors a, .attribs a
 {
     color: #999 !important;
     text-decoration: none;
@@ -269,7 +273,7 @@ tr > th:last-child { border-right: 1px solid #ddd; }
     margin: 0;
 }
 
-.prettyprint
+.source
 {
     border: 1px solid #ddd;
     width: 80%;
@@ -280,7 +284,7 @@ tr > th:last-child { border-right: 1px solid #ddd; }
     width: inherit;
 }
 
-.prettyprint code
+.source code
 {
     font-size: 100%;
     line-height: 18px;
diff --git a/docs/tmp.js.html b/docs/tmp.js.html
index 7203f53..6552b27 100644
--- a/docs/tmp.js.html
+++ b/docs/tmp.js.html
@@ -29,7 +29,7 @@
             <pre class="prettyprint source linenums"><code>/*!
  * Tmp
  *
- * Copyright (c) 2011-2015 KARASZI Istvan &lt;github@spam.raszi.hu>
+ * Copyright (c) 2011-2017 KARASZI Istvan &lt;github@spam.raszi.hu>
  *
  * MIT Licensed
  */
@@ -38,21 +38,16 @@
  * Module dependencies.
  */
 const fs = require('fs');
+const os = require('os');
 const path = require('path');
 const crypto = require('crypto');
-const osTmpDir = require('os-tmpdir');
-const _c = process.binding('constants');
+const _c = { fs: fs.constants, os: os.constants };
+const rimraf = require('rimraf');
 
 /*
  * The working inner variables.
  */
 const
-  /**
-   * The temporary directory.
-   * @type {string}
-   */
-  tmpDir = osTmpDir(),
-
   // the random characters to choose from
   RANDOM_CHARS = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',
 
@@ -62,107 +57,25 @@ const
 
   CREATE_FLAGS = (_c.O_CREAT || _c.fs.O_CREAT) | (_c.O_EXCL || _c.fs.O_EXCL) | (_c.O_RDWR || _c.fs.O_RDWR),
 
+  // constants are off on the windows platform and will not match the actual errno codes
+  IS_WIN32 = os.platform() === 'win32',
   EBADF = _c.EBADF || _c.os.errno.EBADF,
   ENOENT = _c.ENOENT || _c.os.errno.ENOENT,
 
-  DIR_MODE = 448 /* 0o700 */,
-  FILE_MODE = 384 /* 0o600 */,
-
-  // this will hold the objects need to be removed on exit
-  _removeObjects = [];
-
-var
-  _gracefulCleanup = false,
-  _uncaughtException = false;
-
-/**
- * Random name generator based on crypto.
- * Adapted from http://blog.tompawlak.org/how-to-generate-random-values-nodejs-javascript
- *
- * @param {number} howMany
- * @returns {string} the generated random name
- * @private
- */
-function _randomChars(howMany) {
-  var
-    value = [],
-    rnd = null;
-
-  // make sure that we do not fail because we ran out of entropy
-  try {
-    rnd = crypto.randomBytes(howMany);
-  } catch (e) {
-    rnd = crypto.pseudoRandomBytes(howMany);
-  }
-
-  for (var i = 0; i &lt; howMany; i++) {
-    value.push(RANDOM_CHARS[rnd[i] % RANDOM_CHARS.length]);
-  }
+  DIR_MODE = 0o700 /* 448 */,
+  FILE_MODE = 0o600 /* 384 */,
 
-  return value.join('');
-}
+  EXIT = 'exit',
 
-/**
- * Checks whether the `obj` parameter is defined or not.
- *
- * @param {Object} obj
- * @returns {boolean} true if the object is undefined
- * @private
- */
-function _isUndefined(obj) {
-  return typeof obj === 'undefined';
-}
-
-/**
- * Parses the function arguments.
- *
- * This function helps to have optional arguments.
- *
- * @param {(Options|Function)} options
- * @param {Function} callback
- * @returns {Array} parsed arguments
- * @private
- */
-function _parseArguments(options, callback) {
-  if (typeof options == 'function') {
-    var
-      tmp = options,
-      options = callback || {},
-      callback = tmp;
-  } else if (typeof options == 'undefined') {
-    options = {};
-  }
-
-  return [options, callback];
-}
-
-/**
- * Generates a new temporary name.
- *
- * @param {Object} opts
- * @returns {string} the new random name according to opts
- * @private
- */
-function _generateTmpName(opts) {
-  if (opts.name) {
-    return path.join(opts.dir || tmpDir, opts.name);
-  }
-
-  // mkstemps like template
-  if (opts.template) {
-    return opts.template.replace(TEMPLATE_PATTERN, _randomChars(6));
-  }
+  // this will hold the objects need to be removed on exit
+  _removeObjects = [],
 
-  // prefix and postfix
-  const name = [
-    opts.prefix || 'tmp-',
-    process.pid,
-    _randomChars(12),
-    opts.postfix || ''
-  ].join('');
+  // API change in fs.rmdirSync leads to error when passing in a second parameter, e.g. the callback
+  FN_RMDIR_SYNC = fs.rmdirSync.bind(fs),
+  FN_RIMRAF_SYNC = rimraf.sync;
 
-  return path.join(opts.dir || tmpDir, name);
-}
+let
+  _gracefulCleanup = false;
 
 /**
  * Gets a temporary file name.
@@ -171,31 +84,37 @@ function _generateTmpName(opts) {
  * @param {?tmpNameCallback} callback the callback function
  */
 function tmpName(options, callback) {
-  var
+  const
     args = _parseArguments(options, callback),
     opts = args[0],
-    cb = args[1],
-    tries = opts.tries || DEFAULT_TRIES;
-
-  if (isNaN(tries) || tries &lt; 0)
-    return cb(new Error('Invalid tries'));
+    cb = args[1];
 
-  if (opts.template &amp;&amp; !opts.template.match(TEMPLATE_PATTERN))
-    return cb(new Error('Invalid template provided'));
+  try {
+    _assertAndSanitizeOptions(opts);
+  } catch (err) {
+    return cb(err);
+  }
 
+  let tries = opts.tries;
   (function _getUniqueName() {
-    const name = _generateTmpName(opts);
+    try {
+      const name = _generateTmpName(opts);
 
-    // check whether the path exists then retry if needed
-    fs.stat(name, function (err) {
-      if (!err) {
-        if (tries-- > 0) return _getUniqueName();
+      // check whether the path exists then retry if needed
+      fs.stat(name, function (err) {
+        /* istanbul ignore else */
+        if (!err) {
+          /* istanbul ignore else */
+          if (tries-- > 0) return _getUniqueName();
 
-        return cb(new Error('Could not get a unique tmp filename, max tries reached ' + name));
-      }
+          return cb(new Error('Could not get a unique tmp filename, max tries reached ' + name));
+        }
 
-      cb(null, name);
-    });
+        cb(null, name);
+      });
+    } catch (err) {
+      cb(err);
+    }
   }());
 }
 
@@ -207,17 +126,13 @@ function tmpName(options, callback) {
  * @throws {Error} if the options are invalid or could not generate a filename
  */
 function tmpNameSync(options) {
-  var
+  const
     args = _parseArguments(options),
-    opts = args[0],
-    tries = opts.tries || DEFAULT_TRIES;
-
-  if (isNaN(tries) || tries &lt; 0)
-    throw new Error('Invalid tries');
+    opts = args[0];
 
-  if (opts.template &amp;&amp; !opts.template.match(TEMPLATE_PATTERN))
-    throw new Error('Invalid template provided');
+  _assertAndSanitizeOptions(opts);
 
+  let tries = opts.tries;
   do {
     const name = _generateTmpName(opts);
     try {
@@ -233,46 +148,36 @@ function tmpNameSync(options) {
 /**
  * Creates and opens a temporary file.
  *
- * @param {(Options|fileCallback)} options the config options or the callback function
+ * @param {(Options|null|undefined|fileCallback)} options the config options or the callback function or null or undefined
  * @param {?fileCallback} callback
  */
 function file(options, callback) {
-  var
+  const
     args = _parseArguments(options, callback),
     opts = args[0],
     cb = args[1];
 
-  opts.postfix = (_isUndefined(opts.postfix)) ? '.tmp' : opts.postfix;
-
   // gets a temporary filename
   tmpName(opts, function _tmpNameCreated(err, name) {
+    /* istanbul ignore else */
     if (err) return cb(err);
 
     // create and open the file
     fs.open(name, CREATE_FLAGS, opts.mode || FILE_MODE, function _fileCreated(err, fd) {
+      /* istanbu ignore else */
       if (err) return cb(err);
 
       if (opts.discardDescriptor) {
-        return fs.close(fd, function _discardCallback(err) {
-          if (err) {
-            // Low probability, and the file exists, so this could be
-            // ignored.  If it isn't we certainly need to unlink the
-            // file, and if that fails too its error is more
-            // important.
-            try {
-              fs.unlinkSync(name);
-            } catch (e) {
-              err = e;
-            }
-            return cb(err);
-          }
-          cb(null, name, undefined, _prepareTmpFileRemoveCallback(name, -1, opts));
+        return fs.close(fd, function _discardCallback(possibleErr) {
+          // the chance of getting an error on close here is rather low and might occur in the most edgiest cases only
+          return cb(possibleErr, name, undefined, _prepareTmpFileRemoveCallback(name, -1, opts, false));
         });
+      } else {
+        // detachDescriptor passes the descriptor whereas discardDescriptor closes it, either way, we no longer care
+        // about the descriptor
+        const discardOrDetachDescriptor = opts.discardDescriptor || opts.detachDescriptor;
+        cb(null, name, fd, _prepareTmpFileRemoveCallback(name, discardOrDetachDescriptor ? -1 : fd, opts, false));
       }
-      if (opts.detachDescriptor) {
-        return cb(null, name, fd, _prepareTmpFileRemoveCallback(name, -1, opts));
-      }
-      cb(null, name, fd, _prepareTmpFileRemoveCallback(name, fd, opts));
     });
   });
 }
@@ -285,59 +190,26 @@ function file(options, callback) {
  * @throws {Error} if cannot create a file
  */
 function fileSync(options) {
-  var
+  const
     args = _parseArguments(options),
     opts = args[0];
 
-  opts.postfix = opts.postfix || '.tmp';
-
+  const discardOrDetachDescriptor = opts.discardDescriptor || opts.detachDescriptor;
   const name = tmpNameSync(opts);
-  const fd = fs.openSync(name, CREATE_FLAGS, opts.mode || FILE_MODE);
+  var fd = fs.openSync(name, CREATE_FLAGS, opts.mode || FILE_MODE);
+  /* istanbul ignore else */
+  if (opts.discardDescriptor) {
+    fs.closeSync(fd);
+    fd = undefined;
+  }
 
   return {
     name: name,
     fd: fd,
-    removeCallback: _prepareTmpFileRemoveCallback(name, fd, opts)
+    removeCallback: _prepareTmpFileRemoveCallback(name, discardOrDetachDescriptor ? -1 : fd, opts, true)
   };
 }
 
-/**
- * Removes files and folders in a directory recursively.
- *
- * @param {string} root
- * @private
- */
-function _rmdirRecursiveSync(root) {
-  const dirs = [root];
-
-  do {
-    var
-      dir = dirs.pop(),
-      deferred = false,
-      files = fs.readdirSync(dir);
-
-    for (var i = 0, length = files.length; i &lt; length; i++) {
-      var
-        file = path.join(dir, files[i]),
-        stat = fs.lstatSync(file); // lstat so we don't recurse into symlinked directories
-
-      if (stat.isDirectory()) {
-        if (!deferred) {
-          deferred = true;
-          dirs.push(dir);
-        }
-        dirs.push(file);
-      } else {
-        fs.unlinkSync(file);
-      }
-    }
-
-    if (!deferred) {
-      fs.rmdirSync(dir);
-    }
-  } while (dirs.length !== 0);
-}
-
 /**
  * Creates a temporary directory.
  *
@@ -345,20 +217,22 @@ function _rmdirRecursiveSync(root) {
  * @param {?dirCallback} callback
  */
 function dir(options, callback) {
-  var
+  const
     args = _parseArguments(options, callback),
     opts = args[0],
     cb = args[1];
 
   // gets a temporary filename
   tmpName(opts, function _tmpNameCreated(err, name) {
+    /* istanbul ignore else */
     if (err) return cb(err);
 
     // create the directory
     fs.mkdir(name, opts.mode || DIR_MODE, function _dirCreated(err) {
+      /* istanbul ignore else */
       if (err) return cb(err);
 
-      cb(null, name, _prepareTmpDirRemoveCallback(name, opts));
+      cb(null, name, _prepareTmpDirRemoveCallback(name, opts, false));
     });
   });
 }
@@ -371,7 +245,7 @@ function dir(options, callback) {
  * @throws {Error} if it cannot create a directory
  */
 function dirSync(options) {
-  var
+  const
     args = _parseArguments(options),
     opts = args[0];
 
@@ -380,87 +254,138 @@ function dirSync(options) {
 
   return {
     name: name,
-    removeCallback: _prepareTmpDirRemoveCallback(name, opts)
+    removeCallback: _prepareTmpDirRemoveCallback(name, opts, true)
   };
 }
 
 /**
- * Prepares the callback for removal of the temporary file.
+ * Removes files asynchronously.
  *
- * @param {string} name the path of the file
- * @param {number} fd file descriptor
- * @param {Object} opts
- * @returns {fileCallback}
+ * @param {Object} fdPath
+ * @param {Function} next
  * @private
  */
-function _prepareTmpFileRemoveCallback(name, fd, opts) {
-  const removeCallback = _prepareRemoveCallback(function _removeCallback(fdPath) {
+function _removeFileAsync(fdPath, next) {
+  const _handler = function (err) {
+    if (err &amp;&amp; !_isENOENT(err)) {
+      // reraise any unanticipated error
+      return next(err);
+    }
+    next();
+  };
+
+  if (0 &lt;= fdPath[0])
+    fs.close(fdPath[0], function () {
+      fs.unlink(fdPath[1], _handler);
+    });
+  else fs.unlink(fdPath[1], _handler);
+}
+
+/**
+ * Removes files synchronously.
+ *
+ * @param {Object} fdPath
+ * @private
+ */
+function _removeFileSync(fdPath) {
+  let rethrownException = null;
+  try {
+    if (0 &lt;= fdPath[0]) fs.closeSync(fdPath[0]);
+  } catch (e) {
+    // reraise any unanticipated error
+    if (!_isEBADF(e) &amp;&amp; !_isENOENT(e)) throw e;
+  } finally {
     try {
-      if (0 &lt;= fdPath[0]) {
-        fs.closeSync(fdPath[0]);
-      }
+      fs.unlinkSync(fdPath[1]);
     }
     catch (e) {
-      // under some node/windows related circumstances, a temporary file
-      // may have not be created as expected or the file was already closed
-      // by the user, in which case we will simply ignore the error
-      if (e.errno != -EBADF &amp;&amp; e.errno != -ENOENT) {
-        // reraise any unanticipated error
-        throw e;
-      }
+      // reraise any unanticipated error
+      if (!_isENOENT(e)) rethrownException = e;
     }
-    fs.unlinkSync(fdPath[1]);
-  }, [fd, name]);
-
-  if (!opts.keep) {
-    _removeObjects.unshift(removeCallback);
   }
+  if (rethrownException !== null) {
+    throw rethrownException;
+  }
+}
 
-  return removeCallback;
+/**
+ * Prepares the callback for removal of the temporary file.
+ *
+ * Returns either a sync callback or a async callback depending on whether
+ * fileSync or file was called, which is expressed by the sync parameter.
+ *
+ * @param {string} name the path of the file
+ * @param {number} fd file descriptor
+ * @param {Object} opts
+ * @param {boolean} sync
+ * @returns {fileCallback | fileCallbackSync}
+ * @private
+ */
+function _prepareTmpFileRemoveCallback(name, fd, opts, sync) {
+  const removeCallbackSync = _prepareRemoveCallback(_removeFileSync, [fd, name], sync);
+  const removeCallback = _prepareRemoveCallback(_removeFileAsync, [fd, name], sync, removeCallbackSync);
+
+  if (!opts.keep) _removeObjects.unshift(removeCallbackSync);
+
+  return sync ? removeCallbackSync : removeCallback;
 }
 
 /**
  * Prepares the callback for removal of the temporary directory.
  *
+ * Returns either a sync callback or a async callback depending on whether
+ * tmpFileSync or tmpFile was called, which is expressed by the sync parameter.
+ *
  * @param {string} name
  * @param {Object} opts
+ * @param {boolean} sync
  * @returns {Function} the callback
  * @private
  */
-function _prepareTmpDirRemoveCallback(name, opts) {
-  const removeFunction = opts.unsafeCleanup ? _rmdirRecursiveSync : fs.rmdirSync.bind(fs);
-  const removeCallback = _prepareRemoveCallback(removeFunction, name);
-
-  if (!opts.keep) {
-    _removeObjects.unshift(removeCallback);
-  }
-
-  return removeCallback;
+function _prepareTmpDirRemoveCallback(name, opts, sync) {
+  const removeFunction = opts.unsafeCleanup ? rimraf : fs.rmdir.bind(fs);
+  const removeFunctionSync = opts.unsafeCleanup ? FN_RIMRAF_SYNC : FN_RMDIR_SYNC;
+  const removeCallbackSync = _prepareRemoveCallback(removeFunctionSync, name, sync);
+  const removeCallback = _prepareRemoveCallback(removeFunction, name, sync, removeCallbackSync);
+  if (!opts.keep) _removeObjects.unshift(removeCallbackSync);
+
+  return sync ? removeCallbackSync : removeCallback;
 }
 
 /**
  * Creates a guarded function wrapping the removeFunction call.
  *
+ * The cleanup callback is save to be called multiple times.
+ * Subsequent invocations will be ignored.
+ *
  * @param {Function} removeFunction
- * @param {Object} arg
- * @returns {Function}
+ * @param {string} fileOrDirName
+ * @param {boolean} sync
+ * @param {cleanupCallbackSync?} cleanupCallbackSync
+ * @returns {cleanupCallback | cleanupCallbackSync}
  * @private
  */
-function _prepareRemoveCallback(removeFunction, arg) {
-  var called = false;
+function _prepareRemoveCallback(removeFunction, fileOrDirName, sync, cleanupCallbackSync) {
+  let called = false;
 
+  // if sync is true, the next parameter will be ignored
   return function _cleanupCallback(next) {
+
+    /* istanbul ignore else */
     if (!called) {
-      const index = _removeObjects.indexOf(_cleanupCallback);
-      if (index >= 0) {
-        _removeObjects.splice(index, 1);
-      }
+      // remove cleanupCallback from cache
+      const toRemove = cleanupCallbackSync || _cleanupCallback;
+      const index = _removeObjects.indexOf(toRemove);
+      /* istanbul ignore else */
+      if (index >= 0) _removeObjects.splice(index, 1);
 
       called = true;
-      removeFunction(arg);
+      if (sync || removeFunction === FN_RMDIR_SYNC || removeFunction == FN_RIMRAF_SYNC) {
+        return removeFunction(fileOrDirName);
+      } else {
+        return removeFunction(fileOrDirName, next || function() {});
+      }
     }
-
-    if (next) next(null);
   };
 }
 
@@ -470,64 +395,304 @@ function _prepareRemoveCallback(removeFunction, arg) {
  * @private
  */
 function _garbageCollector() {
-  if (_uncaughtException &amp;&amp; !_gracefulCleanup) {
-    return;
-  }
+  /* istanbul ignore else */
+  if (!_gracefulCleanup) return;
 
   // the function being called removes itself from _removeObjects,
   // loop until _removeObjects is empty
   while (_removeObjects.length) {
     try {
-      _removeObjects[0].call(null);
+      _removeObjects[0]();
     } catch (e) {
       // already removed?
     }
   }
 }
 
+/**
+ * Random name generator based on crypto.
+ * Adapted from http://blog.tompawlak.org/how-to-generate-random-values-nodejs-javascript
+ *
+ * @param {number} howMany
+ * @returns {string} the generated random name
+ * @private
+ */
+function _randomChars(howMany) {
+  let
+    value = [],
+    rnd = null;
+
+  // make sure that we do not fail because we ran out of entropy
+  try {
+    rnd = crypto.randomBytes(howMany);
+  } catch (e) {
+    rnd = crypto.pseudoRandomBytes(howMany);
+  }
+
+  for (var i = 0; i &lt; howMany; i++) {
+    value.push(RANDOM_CHARS[rnd[i] % RANDOM_CHARS.length]);
+  }
+
+  return value.join('');
+}
+
+/**
+ * Helper which determines whether a string s is blank, that is undefined, or empty or null.
+ *
+ * @private
+ * @param {string} s
+ * @returns {Boolean} true whether the string s is blank, false otherwise
+ */
+function _isBlank(s) {
+  return s === null || _isUndefined(s) || !s.trim();
+}
+
+/**
+ * Checks whether the `obj` parameter is defined or not.
+ *
+ * @param {Object} obj
+ * @returns {boolean} true if the object is undefined
+ * @private
+ */
+function _isUndefined(obj) {
+  return typeof obj === 'undefined';
+}
+
+/**
+ * Parses the function arguments.
+ *
+ * This function helps to have optional arguments.
+ *
+ * @param {(Options|null|undefined|Function)} options
+ * @param {?Function} callback
+ * @returns {Array} parsed arguments
+ * @private
+ */
+function _parseArguments(options, callback) {
+  /* istanbul ignore else */
+  if (typeof options === 'function') {
+    return [{}, options];
+  }
+
+  /* istanbul ignore else */
+  if (_isUndefined(options)) {
+    return [{}, callback];
+  }
+
+  return [options, callback];
+}
+
+/**
+ * Generates a new temporary name.
+ *
+ * @param {Object} opts
+ * @returns {string} the new random name according to opts
+ * @private
+ */
+function _generateTmpName(opts) {
+
+  const tmpDir = _getTmpDir();
+
+  /* istanbul ignore else */
+  if (!_isUndefined(opts.name))
+    return path.join(tmpDir, opts.dir, opts.name);
+
+  /* istanbul ignore else */
+  if (!_isUndefined(opts.template))
+    return path.join(tmpDir, opts.dir, opts.template).replace(TEMPLATE_PATTERN, _randomChars(6));
+
+  // prefix and postfix
+  const name = [
+    opts.prefix ? opts.prefix : 'tmp',
+    '-',
+    process.pid,
+    '-',
+    _randomChars(12),
+    '-',
+    opts.postfix ? opts.postfix : ''
+  ].join('');
+
+  return path.join(tmpDir, opts.dir, name);
+}
+
+/**
+ * Asserts whether the specified options are valid, also sanitizes options and provides sane defaults for missing
+ * options.
+ *
+ * @param {Options} options
+ * @private
+ */
+function _assertAndSanitizeOptions(options) {
+  const tmpDir = _getTmpDir();
+  /* istanbul ignore else */
+  if (!_isUndefined(options.name))
+    _assertIsRelative(options.name, 'name', tmpDir);
+  /* istanbul ignore else */
+  if (!_isUndefined(options.dir))
+    _assertIsRelative(options.dir, 'dir', tmpDir);
+  /* istanbul ignore else */
+  if (!_isUndefined(options.template)) {
+    _assertIsRelative(options.template, 'template', tmpDir);
+    if (!options.template.match(TEMPLATE_PATTERN))
+      throw new Error(`Invalid template, found "${options.template}".`);
+  }
+  /* istanbul ignore else */
+  if (!_isUndefined(options.tries) &amp;&amp; isNaN(options.tries) || options.tries &lt; 0)
+    throw new Error(`Invalid tries, found "${options.tries}".`);
+
+  // if a name was specified we will try once
+  options.tries = _isUndefined(options.name) ? options.tries || DEFAULT_TRIES : 1;
+  options.keep = !!options.keep;
+  options.detachDescriptor = !!options.detachDescriptor;
+  options.discardDescriptor = !!options.discardDescriptor;
+  options.unsafeCleanup = !!options.unsafeCleanup;
+
+  // sanitize dir, also keep (multiple) blanks if the user, purportedly sane, requests us to
+  options.dir = _isUndefined(options.dir) ? '' : path.relative(tmpDir, _resolvePath(options.dir, tmpDir));
+  options.template = _isUndefined(options.template) ? undefined : path.relative(tmpDir, _resolvePath(options.template, tmpDir));
+  // sanitize further if template is relative to options.dir
+  options.template = _isBlank(options.template) ? undefined : path.relative(options.dir, options.template);
+
+  // for completeness' sake only, also keep (multiple) blanks if the user, purportedly sane, requests us to
+  options.name = _isUndefined(options.name) ? undefined : options.name;
+  options.prefix = _isUndefined(options.prefix) ? '' : options.prefix;
+  options.postfix = _isUndefined(options.postfix) ? '' : options.postfix;
+}
+
+/**
+ * Resolve the specified path name in respect to tmpDir.
+ *
+ * The specified name might include relative path components, e.g. ../
+ * so we need to resolve in order to be sure that is is located inside tmpDir
+ *
+ * @param name
+ * @param tmpDir
+ * @returns {string}
+ * @private
+ */
+function _resolvePath(name, tmpDir) {
+  if (name.startsWith(tmpDir)) {
+    return path.resolve(name);
+  } else {
+    return path.resolve(path.join(tmpDir, name));
+  }
+}
+
+/**
+ * Asserts whether specified name is relative to the specified tmpDir.
+ *
+ * @param {string} name
+ * @param {string} option
+ * @param {string} tmpDir
+ * @throws {Error}
+ * @private
+ */
+function _assertIsRelative(name, option, tmpDir) {
+  if (option === 'name') {
+    // assert that name is not absolute and does not contain a path
+    if (path.isAbsolute(name))
+      throw new Error(`${option} option must not contain an absolute path, found "${name}".`);
+    // must not fail on valid .&lt;name> or ..&lt;name> or similar such constructs
+    let basename = path.basename(name);
+    if (basename === '..' || basename === '.' || basename !== name)
+      throw new Error(`${option} option must not contain a path, found "${name}".`);
+  }
+  else { // if (option === 'dir' || option === 'template') {
+    // assert that dir or template are relative to tmpDir
+    if (path.isAbsolute(name) &amp;&amp; !name.startsWith(tmpDir)) {
+      throw new Error(`${option} option must be relative to "${tmpDir}", found "${name}".`);
+    }
+    let resolvedPath = _resolvePath(name, tmpDir);
+    if (!resolvedPath.startsWith(tmpDir))
+      throw new Error(`${option} option must be relative to "${tmpDir}", found "${resolvedPath}".`);
+  }
+}
+
+/**
+ * Helper for testing against EBADF to compensate changes made to Node 7.x under Windows.
+ *
+ * @private
+ */
+function _isEBADF(error) {
+  return _isExpectedError(error, -EBADF, 'EBADF');
+}
+
+/**
+ * Helper for testing against ENOENT to compensate changes made to Node 7.x under Windows.
+ *
+ * @private
+ */
+function _isENOENT(error) {
+  return _isExpectedError(error, -ENOENT, 'ENOENT');
+}
+
+/**
+ * Helper to determine whether the expected error code matches the actual code and errno,
+ * which will differ between the supported node versions.
+ *
+ * - Node >= 7.0:
+ *   error.code {string}
+ *   error.errno {number} any numerical value will be negated
+ *
+ * CAVEAT
+ *
+ * On windows, the errno for EBADF is -4083 but os.constants.errno.EBADF is different and we must assume that ENOENT
+ * is no different here.
+ *
+ * @param {SystemError} error
+ * @param {number} errno
+ * @param {string} code
+ * @private
+ */
+function _isExpectedError(error, errno, code) {
+  return IS_WIN32 ? error.code === code : error.code === code &amp;&amp; error.errno === errno;
+}
+
 /**
  * Sets the graceful cleanup.
  *
- * Also removes the created files and directories when an uncaught exception occurs.
+ * If graceful cleanup is set, tmp will remove all controlled temporary objects on process exit, otherwise the
+ * temporary objects will remain in place, waiting to be cleaned up on system restart or otherwise scheduled temporary
+ * object removals.
  */
 function setGracefulCleanup() {
   _gracefulCleanup = true;
 }
 
-const version = process.versions.node.split('.').map(function (value) {
-  return parseInt(value, 10);
-});
-
-if (version[0] === 0 &amp;&amp; (version[1] &lt; 9 || version[1] === 9 &amp;&amp; version[2] &lt; 5)) {
-  process.addListener('uncaughtException', function _uncaughtExceptionThrown(err) {
-    _uncaughtException = true;
-    _garbageCollector();
-
-    throw err;
-  });
+/**
+ * Returns the currently configured tmp dir from os.tmpdir().
+ *
+ * @private
+ * @returns {string} the currently configured tmp dir
+ */
+function _getTmpDir() {
+  return path.resolve(os.tmpdir());
 }
 
-process.addListener('exit', function _exit(code) {
-  if (code) _uncaughtException = true;
-  _garbageCollector();
-});
+// Install process exit listener
+process.addListener(EXIT, _garbageCollector);
 
 /**
  * Configuration options.
  *
  * @typedef {Object} Options
+ * @property {?boolean} keep the temporary object (file or dir) will not be garbage collected
  * @property {?number} tries the number of tries before give up the name generation
+ * @property (?int) mode the access mode, defaults are 0o700 for directories and 0o600 for files
  * @property {?string} template the "mkstemp" like filename template
- * @property {?string} name fix name
- * @property {?string} dir the tmp directory to use
+ * @property {?string} name fixed name relative to tmpdir or the specified dir option
+ * @property {?string} dir tmp directory relative to the system tmp directory to use
  * @property {?string} prefix prefix for the generated name
  * @property {?string} postfix postfix for the generated name
+ * @property {?boolean} unsafeCleanup recursively removes the created temporary directory, even when it's not empty
+ * @property {?boolean} detachDescriptor detaches the file descriptor, caller is responsible for closing the file, tmp will no longer try closing the file during garbage collection
+ * @property {?boolean} discardDescriptor discards the file descriptor (closes file, fd is -1), tmp will no longer try closing the file during garbage collection
  */
 
 /**
  * @typedef {Object} FileSyncObject
  * @property {string} name the name of the file
- * @property {string} fd the file descriptor
+ * @property {string} fd the file descriptor or -1 if the fd has been discarded
  * @property {fileCallback} removeCallback the callback function to remove the file
  */
 
@@ -547,10 +712,18 @@ process.addListener('exit', function _exit(code) {
  * @callback fileCallback
  * @param {?Error} err the error object if anything goes wrong
  * @param {string} name the temporary file name
- * @param {number} fd the file descriptor
+ * @param {number} fd the file descriptor or -1 if the fd had been discarded
  * @param {cleanupCallback} fn the cleanup callback function
  */
 
+/**
+ * @callback fileCallbackSync
+ * @param {?Error} err the error object if anything goes wrong
+ * @param {string} name the temporary file name
+ * @param {number} fd the file descriptor or -1 if the fd had been discarded
+ * @param {cleanupCallbackSync} fn the cleanup callback function
+ */
+
 /**
  * @callback dirCallback
  * @param {?Error} err the error object if anything goes wrong
@@ -558,11 +731,24 @@ process.addListener('exit', function _exit(code) {
  * @param {cleanupCallback} fn the cleanup callback function
  */
 
+/**
+ * @callback dirCallbackSync
+ * @param {?Error} err the error object if anything goes wrong
+ * @param {string} name the temporary file name
+ * @param {cleanupCallbackSync} fn the cleanup callback function
+ */
+
 /**
  * Removes the temporary created file or directory.
  *
  * @callback cleanupCallback
- * @param {simpleCallback} [next] function to call after entry was removed
+ * @param {simpleCallback} [next] function to call whenever the tmp object needs to be removed
+ */
+
+/**
+ * Removes the temporary created file or directory.
+ *
+ * @callback cleanupCallbackSync
  */
 
 /**
@@ -573,7 +759,16 @@ process.addListener('exit', function _exit(code) {
  */
 
 // exporting all the needed methods
-module.exports.tmpdir = tmpDir;
+
+// evaluate os.tmpdir() lazily, mainly for simplifying testing but it also will
+// allow users to reconfigure the temporary directory
+Object.defineProperty(module.exports, 'tmpdir', {
+  enumerable: true,
+  configurable: false,
+  get: function () {
+    return _getTmpDir();
+  }
+});
 
 module.exports.dir = dir;
 module.exports.dirSync = dirSync;
@@ -595,13 +790,13 @@ module.exports.setGracefulCleanup = setGracefulCleanup;
 </div>
 
 <nav>
-    <h2><a href="index.html">Home</a></h2><h3>Global</h3><ul><li><a href="global.html#dir">dir</a></li><li><a href="global.html#dirSync">dirSync</a></li><li><a href="global.html#file">file</a></li><li><a href="global.html#fileSync">fileSync</a></li><li><a href="global.html#setGracefulCleanup">setGracefulCleanup</a></li><li><a href="global.html#tmpDir">tmpDir</a></li><li><a href="global.html#tmpName">tmpName</a></li><li><a href="global.html#tmpNameSync">tmpNameSync</a></li></ul>
+    <h2><a href="index.html">Home</a></h2><h3>Global</h3><ul><li><a href="global.html#dir">dir</a></li><li><a href="global.html#dirSync">dirSync</a></li><li><a href="global.html#file">file</a></li><li><a href="global.html#fileSync">fileSync</a></li><li><a href="global.html#setGracefulCleanup">setGracefulCleanup</a></li><li><a href="global.html#tmpName">tmpName</a></li><li><a href="global.html#tmpNameSync">tmpNameSync</a></li></ul>
 </nav>
 
 <br class="clear">
 
 <footer>
-    Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.4.3</a> on Sat Nov 26 2016 21:53:28 GMT+0100 (CET)
+    Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.3</a> on Sat Feb 08 2020 01:04:48 GMT+0100 (GMT+01:00)
 </footer>
 
 <script> prettyPrint(); </script>
diff --git a/lib/tmp.js b/lib/tmp.js
index 05a65fb..4cb77cb 100644
--- a/lib/tmp.js
+++ b/lib/tmp.js
@@ -13,9 +13,7 @@ const fs = require('fs');
 const os = require('os');
 const path = require('path');
 const crypto = require('crypto');
-const _c = fs.constants && os.constants ?
-  { fs: fs.constants, os: os.constants } :
-  process.binding('constants');
+const _c = { fs: fs.constants, os: os.constants };
 const rimraf = require('rimraf');
 
 /*
@@ -31,16 +29,16 @@ const
 
   CREATE_FLAGS = (_c.O_CREAT || _c.fs.O_CREAT) | (_c.O_EXCL || _c.fs.O_EXCL) | (_c.O_RDWR || _c.fs.O_RDWR),
 
+  // constants are off on the windows platform and will not match the actual errno codes
+  IS_WIN32 = os.platform() === 'win32',
   EBADF = _c.EBADF || _c.os.errno.EBADF,
   ENOENT = _c.ENOENT || _c.os.errno.ENOENT,
 
-  DIR_MODE = 448 /* 0o700 */,
-  FILE_MODE = 384 /* 0o600 */,
+  DIR_MODE = 0o700 /* 448 */,
+  FILE_MODE = 0o600 /* 384 */,
 
   EXIT = 'exit',
 
-  SIGINT = 'SIGINT',
-
   // this will hold the objects need to be removed on exit
   _removeObjects = [],
 
@@ -48,115 +46,9 @@ const
   FN_RMDIR_SYNC = fs.rmdirSync.bind(fs),
   FN_RIMRAF_SYNC = rimraf.sync;
 
-var
+let
   _gracefulCleanup = false;
 
-/**
- * Random name generator based on crypto.
- * Adapted from http://blog.tompawlak.org/how-to-generate-random-values-nodejs-javascript
- *
- * @param {number} howMany
- * @returns {string} the generated random name
- * @private
- */
-function _randomChars(howMany) {
-  var
-    value = [],
-    rnd = null;
-
-  // make sure that we do not fail because we ran out of entropy
-  try {
-    rnd = crypto.randomBytes(howMany);
-  } catch (e) {
-    rnd = crypto.pseudoRandomBytes(howMany);
-  }
-
-  for (var i = 0; i < howMany; i++) {
-    value.push(RANDOM_CHARS[rnd[i] % RANDOM_CHARS.length]);
-  }
-
-  return value.join('');
-}
-
-/**
- * Checks whether the `obj` parameter is defined or not.
- *
- * @param {Object} obj
- * @returns {boolean} true if the object is undefined
- * @private
- */
-function _isUndefined(obj) {
-  return typeof obj === 'undefined';
-}
-
-/**
- * Parses the function arguments.
- *
- * This function helps to have optional arguments.
- *
- * @param {(Options|Function)} options
- * @param {Function} callback
- * @returns {Array} parsed arguments
- * @private
- */
-function _parseArguments(options, callback) {
-  /* istanbul ignore else */
-  if (typeof options === 'function') {
-    return [{}, options];
-  }
-
-  /* istanbul ignore else */
-  if (_isUndefined(options)) {
-    return [{}, callback];
-  }
-
-  return [options, callback];
-}
-
-/**
- * Generates a new temporary name.
- *
- * @param {Object} opts
- * @returns {string} the new random name according to opts
- * @private
- */
-function _generateTmpName(opts) {
-
-  const tmpDir = _getTmpDir();
-
-  // fail early on missing tmp dir
-  if (isBlank(opts.dir) && isBlank(tmpDir)) {
-    throw new Error('No tmp dir specified');
-  }
-
-  /* istanbul ignore else */
-  if (!isBlank(opts.name)) {
-    return path.join(opts.dir || tmpDir, opts.name);
-  }
-
-  // mkstemps like template
-  // opts.template has already been guarded in tmpName() below
-  /* istanbul ignore else */
-  if (opts.template) {
-    var template = opts.template;
-    // make sure that we prepend the tmp path if none was given
-    /* istanbul ignore else */
-    if (path.basename(template) === template)
-      template = path.join(opts.dir || tmpDir, template);
-    return template.replace(TEMPLATE_PATTERN, _randomChars(6));
-  }
-
-  // prefix and postfix
-  const name = [
-    (isBlank(opts.prefix) ? 'tmp-' : opts.prefix),
-    process.pid,
-    _randomChars(12),
-    (opts.postfix ? opts.postfix : '')
-  ].join('');
-
-  return path.join(opts.dir || tmpDir, name);
-}
-
 /**
  * Gets a temporary file name.
  *
@@ -164,20 +56,18 @@ function _generateTmpName(opts) {
  * @param {?tmpNameCallback} callback the callback function
  */
 function tmpName(options, callback) {
-  var
+  const
     args = _parseArguments(options, callback),
     opts = args[0],
-    cb = args[1],
-    tries = !isBlank(opts.name) ? 1 : opts.tries || DEFAULT_TRIES;
-
-  /* istanbul ignore else */
-  if (isNaN(tries) || tries < 0)
-    return cb(new Error('Invalid tries'));
+    cb = args[1];
 
-  /* istanbul ignore else */
-  if (opts.template && !opts.template.match(TEMPLATE_PATTERN))
-    return cb(new Error('Invalid template provided'));
+  try {
+    _assertAndSanitizeOptions(opts);
+  } catch (err) {
+    return cb(err);
+  }
 
+  let tries = opts.tries;
   (function _getUniqueName() {
     try {
       const name = _generateTmpName(opts);
@@ -208,19 +98,13 @@ function tmpName(options, callback) {
  * @throws {Error} if the options are invalid or could not generate a filename
  */
 function tmpNameSync(options) {
-  var
+  const
     args = _parseArguments(options),
-    opts = args[0],
-    tries = !isBlank(opts.name) ? 1 : opts.tries || DEFAULT_TRIES;
-
-  /* istanbul ignore else */
-  if (isNaN(tries) || tries < 0)
-    throw new Error('Invalid tries');
+    opts = args[0];
 
-  /* istanbul ignore else */
-  if (opts.template && !opts.template.match(TEMPLATE_PATTERN))
-    throw new Error('Invalid template provided');
+  _assertAndSanitizeOptions(opts);
 
+  let tries = opts.tries;
   do {
     const name = _generateTmpName(opts);
     try {
@@ -236,11 +120,11 @@ function tmpNameSync(options) {
 /**
  * Creates and opens a temporary file.
  *
- * @param {(Options|fileCallback)} options the config options or the callback function
+ * @param {(Options|null|undefined|fileCallback)} options the config options or the callback function or null or undefined
  * @param {?fileCallback} callback
  */
 function file(options, callback) {
-  var
+  const
     args = _parseArguments(options, callback),
     opts = args[0],
     cb = args[1];
@@ -252,32 +136,17 @@ function file(options, callback) {
 
     // create and open the file
     fs.open(name, CREATE_FLAGS, opts.mode || FILE_MODE, function _fileCreated(err, fd) {
-      /* istanbul ignore else */
+      /* istanbu ignore else */
       if (err) return cb(err);
 
-      // FIXME overall handling of opts.discardDescriptor is off
       if (opts.discardDescriptor) {
-        // FIXME? must not unlink as the user expects the filename to be reserved
-        return fs.close(fd, function _discardCallback(err) {
-          /* istanbul ignore else */
-          if (err) {
-            // Low probability, and the file exists, so this could be
-            // ignored.  If it isn't we certainly need to unlink the
-            // file, and if that fails too its error is more
-            // important.
-            try {
-              fs.unlinkSync(name);
-            } catch (e) {
-              if (!isENOENT(e)) {
-                err = e;
-              }
-            }
-            return cb(err);
-          }
-          cb(null, name, undefined, _prepareTmpFileRemoveCallback(name, -1, opts));
+        return fs.close(fd, function _discardCallback(possibleErr) {
+          // the chance of getting an error on close here is rather low and might occur in the most edgiest cases only
+          return cb(possibleErr, name, undefined, _prepareTmpFileRemoveCallback(name, -1, opts, false));
         });
       } else {
-        // FIXME detachDescriptor passes the descriptor whereas discardDescriptor closes it
+        // detachDescriptor passes the descriptor whereas discardDescriptor closes it, either way, we no longer care
+        // about the descriptor
         const discardOrDetachDescriptor = opts.discardDescriptor || opts.detachDescriptor;
         cb(null, name, fd, _prepareTmpFileRemoveCallback(name, discardOrDetachDescriptor ? -1 : fd, opts, false));
       }
@@ -293,7 +162,7 @@ function file(options, callback) {
  * @throws {Error} if cannot create a file
  */
 function fileSync(options) {
-  var
+  const
     args = _parseArguments(options),
     opts = args[0];
 
@@ -320,7 +189,7 @@ function fileSync(options) {
  * @param {?dirCallback} callback
  */
 function dir(options, callback) {
-  var
+  const
     args = _parseArguments(options, callback),
     opts = args[0],
     cb = args[1];
@@ -348,7 +217,7 @@ function dir(options, callback) {
  * @throws {Error} if it cannot create a directory
  */
 function dirSync(options) {
-  var
+  const
     args = _parseArguments(options),
     opts = args[0];
 
@@ -370,7 +239,7 @@ function dirSync(options) {
  */
 function _removeFileAsync(fdPath, next) {
   const _handler = function (err) {
-    if (err && !isENOENT(err)) {
+    if (err && !_isENOENT(err)) {
       // reraise any unanticipated error
       return next(err);
     }
@@ -391,19 +260,19 @@ function _removeFileAsync(fdPath, next) {
  * @private
  */
 function _removeFileSync(fdPath) {
-  var rethrownException = null;
+  let rethrownException = null;
   try {
     if (0 <= fdPath[0]) fs.closeSync(fdPath[0]);
   } catch (e) {
     // reraise any unanticipated error
-    if (!isEBADF(e) && !isENOENT(e)) throw e;
+    if (!_isEBADF(e) && !_isENOENT(e)) throw e;
   } finally {
     try {
       fs.unlinkSync(fdPath[1]);
     }
     catch (e) {
       // reraise any unanticipated error
-      if (!isENOENT(e)) rethrownException = e;
+      if (!_isENOENT(e)) rethrownException = e;
     }
   }
   if (rethrownException !== null) {
@@ -469,7 +338,7 @@ function _prepareTmpDirRemoveCallback(name, opts, sync) {
  * @private
  */
 function _prepareRemoveCallback(removeFunction, fileOrDirName, sync, cleanupCallbackSync) {
-  var called = false;
+  let called = false;
 
   // if sync is true, the next parameter will be ignored
   return function _cleanupCallback(next) {
@@ -513,179 +382,303 @@ function _garbageCollector() {
 }
 
 /**
- * Helper for testing against EBADF to compensate changes made to Node 7.x under Windows.
+ * Random name generator based on crypto.
+ * Adapted from http://blog.tompawlak.org/how-to-generate-random-values-nodejs-javascript
+ *
+ * @param {number} howMany
+ * @returns {string} the generated random name
+ * @private
  */
-function isEBADF(error) {
-  return isExpectedError(error, -EBADF, 'EBADF');
+function _randomChars(howMany) {
+  let
+    value = [],
+    rnd = null;
+
+  // make sure that we do not fail because we ran out of entropy
+  try {
+    rnd = crypto.randomBytes(howMany);
+  } catch (e) {
+    rnd = crypto.pseudoRandomBytes(howMany);
+  }
+
+  for (var i = 0; i < howMany; i++) {
+    value.push(RANDOM_CHARS[rnd[i] % RANDOM_CHARS.length]);
+  }
+
+  return value.join('');
 }
 
 /**
- * Helper for testing against ENOENT to compensate changes made to Node 7.x under Windows.
+ * Helper which determines whether a string s is blank, that is undefined, or empty or null.
+ *
+ * @private
+ * @param {string} s
+ * @returns {Boolean} true whether the string s is blank, false otherwise
  */
-function isENOENT(error) {
-  return isExpectedError(error, -ENOENT, 'ENOENT');
+function _isBlank(s) {
+  return s === null || _isUndefined(s) || !s.trim();
 }
 
 /**
- * Helper to determine whether the expected error code matches the actual code and errno,
- * which will differ between the supported node versions.
- *
- * - Node >= 7.0:
- *   error.code {string}
- *   error.errno {string|number} any numerical value will be negated
+ * Checks whether the `obj` parameter is defined or not.
  *
- * - Node >= 6.0 < 7.0:
- *   error.code {string}
- *   error.errno {number} negated
+ * @param {Object} obj
+ * @returns {boolean} true if the object is undefined
+ * @private
+ */
+function _isUndefined(obj) {
+  return typeof obj === 'undefined';
+}
+
+/**
+ * Parses the function arguments.
  *
- * - Node >= 4.0 < 6.0: introduces SystemError
- *   error.code {string}
- *   error.errno {number} negated
+ * This function helps to have optional arguments.
  *
- * - Node >= 0.10 < 4.0:
- *   error.code {number} negated
- *   error.errno n/a
+ * @param {(Options|null|undefined|Function)} options
+ * @param {?Function} callback
+ * @returns {Array} parsed arguments
+ * @private
  */
-function isExpectedError(error, code, errno) {
-  return error.code === code || error.code === errno;
+function _parseArguments(options, callback) {
+  /* istanbul ignore else */
+  if (typeof options === 'function') {
+    return [{}, options];
+  }
+
+  /* istanbul ignore else */
+  if (_isUndefined(options)) {
+    return [{}, callback];
+  }
+
+  return [options, callback];
 }
 
 /**
- * Helper which determines whether a string s is blank, that is undefined, or empty or null.
+ * Generates a new temporary name.
  *
+ * @param {Object} opts
+ * @returns {string} the new random name according to opts
  * @private
- * @param {string} s
- * @returns {Boolean} true whether the string s is blank, false otherwise
  */
-function isBlank(s) {
-  return s === null || s === undefined || !s.trim();
+function _generateTmpName(opts) {
+
+  const tmpDir = _getTmpDir();
+
+  /* istanbul ignore else */
+  if (!_isUndefined(opts.name))
+    return path.join(tmpDir, opts.dir, opts.name);
+
+  /* istanbul ignore else */
+  if (!_isUndefined(opts.template))
+    return path.join(tmpDir, opts.dir, opts.template).replace(TEMPLATE_PATTERN, _randomChars(6));
+
+  // prefix and postfix
+  const name = [
+    opts.prefix ? opts.prefix : 'tmp',
+    '-',
+    process.pid,
+    '-',
+    _randomChars(12),
+    opts.postfix ? '-' + opts.postfix : ''
+  ].join('');
+
+  return path.join(tmpDir, opts.dir, name);
 }
 
 /**
- * Sets the graceful cleanup.
+ * Asserts whether the specified options are valid, also sanitizes options and provides sane defaults for missing
+ * options.
+ *
+ * @param {Options} options
+ * @private
  */
-function setGracefulCleanup() {
-  _gracefulCleanup = true;
+function _assertAndSanitizeOptions(options) {
+  const tmpDir = _getTmpDir();
+  /* istanbul ignore else */
+  if (!_isUndefined(options.name))
+    _assertIsRelative(options.name, 'name', tmpDir);
+  /* istanbul ignore else */
+  if (!_isUndefined(options.dir))
+    _assertIsRelative(options.dir, 'dir', tmpDir);
+  /* istanbul ignore else */
+  if (!_isUndefined(options.template)) {
+    _assertIsRelative(options.template, 'template', tmpDir);
+    if (!options.template.match(TEMPLATE_PATTERN))
+      throw new Error(`Invalid template, found "${options.template}".`);
+  }
+  /* istanbul ignore else */
+  if (!_isUndefined(options.tries) && isNaN(options.tries) || options.tries < 0)
+    throw new Error(`Invalid tries, found "${options.tries}".`);
+
+  // if a name was specified we will try once
+  options.tries = _isUndefined(options.name) ? options.tries || DEFAULT_TRIES : 1;
+  options.keep = !!options.keep;
+  options.detachDescriptor = !!options.detachDescriptor;
+  options.discardDescriptor = !!options.discardDescriptor;
+  options.unsafeCleanup = !!options.unsafeCleanup;
+
+  // sanitize dir, also keep (multiple) blanks if the user, purportedly sane, requests us to
+  options.dir = _isUndefined(options.dir) ? '' : path.relative(tmpDir, _resolvePath(options.dir, tmpDir));
+  options.template = _isUndefined(options.template) ? undefined : path.relative(tmpDir, _resolvePath(options.template, tmpDir));
+  // sanitize further if template is relative to options.dir
+  options.template = _isBlank(options.template) ? undefined : path.relative(options.dir, options.template);
+
+  // for completeness' sake only, also keep (multiple) blanks if the user, purportedly sane, requests us to
+  options.name = _isUndefined(options.name) ? undefined : _sanitizeName(options.name);
+  options.prefix = _isUndefined(options.prefix) ? '' : options.prefix;
+  options.postfix = _isUndefined(options.postfix) ? '' : options.postfix;
 }
 
 /**
- * Returns the currently configured tmp dir from os.tmpdir().
+ * Resolve the specified path name in respect to tmpDir.
  *
+ * The specified name might include relative path components, e.g. ../
+ * so we need to resolve in order to be sure that is is located inside tmpDir
+ *
+ * @param name
+ * @param tmpDir
+ * @returns {string}
  * @private
- * @returns {string} the currently configured tmp dir
  */
-function _getTmpDir() {
-  return os.tmpdir();
+function _resolvePath(name, tmpDir) {
+  const sanitizedName = _sanitizeName(name);
+  if (sanitizedName.startsWith(tmpDir)) {
+    return path.resolve(sanitizedName);
+  } else {
+    return path.resolve(path.join(tmpDir, sanitizedName));
+  }
 }
 
 /**
- * If there are multiple different versions of tmp in place, make sure that
- * we recognize the old listeners.
+ * Sanitize the specified path name by removing all quote characters.
  *
- * @param {Function} listener
+ * @param name
+ * @returns {string}
  * @private
- * @returns {Boolean} true whether listener is a legacy listener
  */
-function _is_legacy_listener(listener) {
-  return (listener.name === '_exit' || listener.name === '_uncaughtExceptionThrown')
-    && listener.toString().indexOf('_garbageCollector();') > -1;
+function _sanitizeName(name) {
+  if (_isBlank(name)) {
+    return name;
+  }
+  return name.replace(/["']/g, '');
 }
 
 /**
- * Safely install SIGINT listener.
- *
- * NOTE: this will only work on OSX and Linux.
+ * Asserts whether specified name is relative to the specified tmpDir.
  *
+ * @param {string} name
+ * @param {string} option
+ * @param {string} tmpDir
+ * @throws {Error}
  * @private
  */
-function _safely_install_sigint_listener() {
-
-  const listeners = process.listeners(SIGINT);
-  const existingListeners = [];
-  for (let i = 0, length = listeners.length; i < length; i++) {
-    const lstnr = listeners[i];
-    /* istanbul ignore else */
-    if (lstnr.name === '_tmp$sigint_listener') {
-      existingListeners.push(lstnr);
-      process.removeListener(SIGINT, lstnr);
-    }
+function _assertIsRelative(name, option, tmpDir) {
+  if (option === 'name') {
+    // assert that name is not absolute and does not contain a path
+    if (path.isAbsolute(name))
+      throw new Error(`${option} option must not contain an absolute path, found "${name}".`);
+    // must not fail on valid .<name> or ..<name> or similar such constructs
+    let basename = path.basename(name);
+    if (basename === '..' || basename === '.' || basename !== name)
+      throw new Error(`${option} option must not contain a path, found "${name}".`);
   }
-  process.on(SIGINT, function _tmp$sigint_listener(doExit) {
-    for (let i = 0, length = existingListeners.length; i < length; i++) {
-      // let the existing listener do the garbage collection (e.g. jest sandbox)
-      try {
-        existingListeners[i](false);
-      } catch (err) {
-        // ignore
-      }
-    }
-    try {
-      // force the garbage collector even it is called again in the exit listener
-      _garbageCollector();
-    } finally {
-      if (!!doExit) {
-        process.exit(0);
-      }
+  else { // if (option === 'dir' || option === 'template') {
+    // assert that dir or template are relative to tmpDir
+    if (path.isAbsolute(name) && !name.startsWith(tmpDir)) {
+      throw new Error(`${option} option must be relative to "${tmpDir}", found "${name}".`);
     }
-  });
+    let resolvedPath = _resolvePath(name, tmpDir);
+    if (!resolvedPath.startsWith(tmpDir))
+      throw new Error(`${option} option must be relative to "${tmpDir}", found "${resolvedPath}".`);
+  }
 }
 
 /**
- * Safely install process exit listener.
+ * Helper for testing against EBADF to compensate changes made to Node 7.x under Windows.
  *
  * @private
  */
-function _safely_install_exit_listener() {
-  const listeners = process.listeners(EXIT);
+function _isEBADF(error) {
+  return _isExpectedError(error, -EBADF, 'EBADF');
+}
 
-  // collect any existing listeners
-  const existingListeners = [];
-  for (let i = 0, length = listeners.length; i < length; i++) {
-    const lstnr = listeners[i];
-    /* istanbul ignore else */
-    // TODO: remove support for legacy listeners once release 1.0.0 is out
-    if (lstnr.name === '_tmp$safe_listener' || _is_legacy_listener(lstnr)) {
-      // we must forget about the uncaughtException listener, hopefully it is ours
-      if (lstnr.name !== '_uncaughtExceptionThrown') {
-        existingListeners.push(lstnr);
-      }
-      process.removeListener(EXIT, lstnr);
-    }
-  }
-  // TODO: what was the data parameter good for?
-  process.addListener(EXIT, function _tmp$safe_listener(data) {
-    for (let i = 0, length = existingListeners.length; i < length; i++) {
-      // let the existing listener do the garbage collection (e.g. jest sandbox)
-      try {
-        existingListeners[i](data);
-      } catch (err) {
-        // ignore
-      }
-    }
-    _garbageCollector();
-  });
+/**
+ * Helper for testing against ENOENT to compensate changes made to Node 7.x under Windows.
+ *
+ * @private
+ */
+function _isENOENT(error) {
+  return _isExpectedError(error, -ENOENT, 'ENOENT');
+}
+
+/**
+ * Helper to determine whether the expected error code matches the actual code and errno,
+ * which will differ between the supported node versions.
+ *
+ * - Node >= 7.0:
+ *   error.code {string}
+ *   error.errno {number} any numerical value will be negated
+ *
+ * CAVEAT
+ *
+ * On windows, the errno for EBADF is -4083 but os.constants.errno.EBADF is different and we must assume that ENOENT
+ * is no different here.
+ *
+ * @param {SystemError} error
+ * @param {number} errno
+ * @param {string} code
+ * @private
+ */
+function _isExpectedError(error, errno, code) {
+  return IS_WIN32 ? error.code === code : error.code === code && error.errno === errno;
+}
+
+/**
+ * Sets the graceful cleanup.
+ *
+ * If graceful cleanup is set, tmp will remove all controlled temporary objects on process exit, otherwise the
+ * temporary objects will remain in place, waiting to be cleaned up on system restart or otherwise scheduled temporary
+ * object removals.
+ */
+function setGracefulCleanup() {
+  _gracefulCleanup = true;
+}
+
+/**
+ * Returns the currently configured tmp dir from os.tmpdir().
+ *
+ * @private
+ * @returns {string} the currently configured tmp dir
+ */
+function _getTmpDir() {
+  return path.resolve(_sanitizeName(os.tmpdir()));
 }
 
-_safely_install_exit_listener();
-_safely_install_sigint_listener();
+// Install process exit listener
+process.addListener(EXIT, _garbageCollector);
 
 /**
  * Configuration options.
  *
  * @typedef {Object} Options
+ * @property {?boolean} keep the temporary object (file or dir) will not be garbage collected
  * @property {?number} tries the number of tries before give up the name generation
+ * @property (?int) mode the access mode, defaults are 0o700 for directories and 0o600 for files
  * @property {?string} template the "mkstemp" like filename template
- * @property {?string} name fix name
- * @property {?string} dir the tmp directory to use
+ * @property {?string} name fixed name relative to tmpdir or the specified dir option
+ * @property {?string} dir tmp directory relative to the system tmp directory to use
  * @property {?string} prefix prefix for the generated name
  * @property {?string} postfix postfix for the generated name
  * @property {?boolean} unsafeCleanup recursively removes the created temporary directory, even when it's not empty
+ * @property {?boolean} detachDescriptor detaches the file descriptor, caller is responsible for closing the file, tmp will no longer try closing the file during garbage collection
+ * @property {?boolean} discardDescriptor discards the file descriptor (closes file, fd is -1), tmp will no longer try closing the file during garbage collection
  */
 
 /**
  * @typedef {Object} FileSyncObject
  * @property {string} name the name of the file
- * @property {string} fd the file descriptor
+ * @property {string} fd the file descriptor or -1 if the fd has been discarded
  * @property {fileCallback} removeCallback the callback function to remove the file
  */
 
@@ -705,7 +698,7 @@ _safely_install_sigint_listener();
  * @callback fileCallback
  * @param {?Error} err the error object if anything goes wrong
  * @param {string} name the temporary file name
- * @param {number} fd the file descriptor
+ * @param {number} fd the file descriptor or -1 if the fd had been discarded
  * @param {cleanupCallback} fn the cleanup callback function
  */
 
@@ -713,7 +706,7 @@ _safely_install_sigint_listener();
  * @callback fileCallbackSync
  * @param {?Error} err the error object if anything goes wrong
  * @param {string} name the temporary file name
- * @param {number} fd the file descriptor
+ * @param {number} fd the file descriptor or -1 if the fd had been discarded
  * @param {cleanupCallbackSync} fn the cleanup callback function
  */
 
diff --git a/package.json b/package.json
index 1b8e448..60f0f69 100644
--- a/package.json
+++ b/package.json
@@ -3,6 +3,9 @@
   "version": "0.1.0",
   "description": "Temporary file and directory creator",
   "author": "KARASZI István <github@spam.raszi.hu> (http://raszi.hu/)",
+  "contributors": [
+    "Carsten Klein <trancesilken@gmail.com> (https://github.com/silkentrance)"
+  ],
   "keywords": [
     "temporary",
     "tmp",
@@ -19,7 +22,7 @@
     "url": "http://github.com/raszi/node-tmp/issues"
   },
   "engines": {
-    "node": ">=8"
+    "node": ">=8.17.0"
   },
   "dependencies": {
     "rimraf": "^3.0.0"


Test patch:
diff --git a/test/assertions.js b/test/assertions.js
index 4b98933..170f409 100644
--- a/test/assertions.js
+++ b/test/assertions.js
@@ -23,7 +23,7 @@ module.exports.assertMode = function assertMode(name, mode) {
   // mode values do not work properly on Windows. Ignore “group” and
   // “other” bits then. Ignore execute bit on that platform because it
   // doesn’t exist—even for directories.
-  if (process.platform == 'win32') {
+  if (process.platform === 'win32') {
     assert.equal(stat.mode & 0o600, mode & 0o600);
   } else {
     assert.equal(stat.mode & 0o777, mode);
diff --git a/test/issue129-sigint-test.js b/test/issue129-sigint-test.js
deleted file mode 100644
index 30880d9..0000000
--- a/test/issue129-sigint-test.js
+++ /dev/null
@@ -1,27 +0,0 @@
-/* eslint-disable no-octal */
-// vim: expandtab:ts=2:sw=2
-
-var
-  assert = require('assert'),
-  assertions = require('./assertions'),
-  childProcess = require('./child-process').childProcess;
-
-describe('tmp', function () {
-  describe('issue129: safely install sigint listeners', function () {
-    it('when simulating sandboxed behavior', function (done) {
-      childProcess(this, 'issue129-sigint.json', function (err, stderr, stdout) {
-        if (err) return done(err);
-        if (stderr) {
-          assertions.assertDoesNotStartWith(stderr, 'EEXISTS:MULTIPLE');
-          assertions.assertDoesNotStartWith(stderr, 'ENOAVAIL:');
-          return done();
-        }
-        if (stdout) {
-          assert.equal(stdout, 'EOK');
-          return done();
-        }
-        done(new Error('existing listener has not been called'));
-      });
-    });
-  });
-});
diff --git a/test/issue129-test.js b/test/issue129-test.js
deleted file mode 100644
index 250483a..0000000
--- a/test/issue129-test.js
+++ /dev/null
@@ -1,30 +0,0 @@
-/* eslint-disable no-octal */
-// vim: expandtab:ts=2:sw=2
-
-var
-  assert = require('assert'),
-  assertions = require('./assertions'),
-  childProcess = require('./child-process').childProcess;
-
-describe('tmp', function () {
-  describe('issue129: safely install listeners', function () {
-    it('when simulating sandboxed behavior', function (done) {
-      childProcess(this, 'issue129.json', function (err, stderr, stdout) {
-        if (err) return done(err);
-        if (!stdout && !stderr) return done(new Error('stderr or stdout expected'));
-        if (stderr) {
-          assertions.assertDoesNotStartWith(stderr, 'EEXISTS:LEGACY:EXIT');
-          assertions.assertDoesNotStartWith(stderr, 'EEXISTS:LEGACY:UNCAUGHT');
-          assertions.assertDoesNotStartWith(stderr, 'EEXISTS:NEWSTYLE');
-          assertions.assertDoesNotStartWith(stderr, 'ENOAVAIL:LEGACY:EXIT');
-          assertions.assertDoesNotStartWith(stderr, 'EAVAIL:LEGACY:UNCAUGHT');
-          assertions.assertDoesNotStartWith(stderr, 'ENOAVAIL:NEWSTYLE');
-        }
-        if (stdout) {
-          assert.equal(stdout, 'EOK', 'existing listeners should have been removed and called');
-        }
-        done();
-      });
-    });
-  });
-});
diff --git a/test/mocha.opts b/test/mocha.opts
new file mode 100644
index 0000000..671ed4a
--- /dev/null
+++ b/test/mocha.opts
@@ -0,0 +1,1 @@
+--file ./test/setup-sigint-listener.js
\ No newline at end of file
diff --git a/test/name-sync-test.js b/test/name-sync-test.js
index 8921150..4a686fd 100644
--- a/test/name-sync-test.js
+++ b/test/name-sync-test.js
@@ -7,6 +7,7 @@ const
   inbandStandardTests = require('./name-inband-standard'),
   tmp = require('../lib/tmp');
 
+const isWindows = os.platform() === 'win32';
 
 describe('tmp', function () {
   describe('#tmpNameSync()', function () {
@@ -38,66 +39,46 @@ describe('tmp', function () {
     describe('when running issue specific inband tests', function () {
       describe('on issue #176', function () {
         const origfn = os.tmpdir;
-
-        function _generateSpecName(optsDir, osTmpDir) {
-          return 'opts.dir = "$1", os.tmpdir() = "$2"'.replace('$1', optsDir).replace('$2', osTmpDir);  
-        }
-
-        const failing = ['', '  ', undefined, null];
-        const nonFailing = ['tmp']; // the origfn cannot be trusted as the os may or may not have a valid tmp dir
-
-        describe('must fail on invalid os.tmpdir() and invalid opts.dir', function () {
-          // test all failing permutations
-          for (let oidx = 0; oidx < failing.length; oidx++) {
-            for (let iidx = 0; iidx < failing.length; iidx++) {
-              it(_generateSpecName(failing[iidx], failing[oidx]), function () {
-                os.tmpdir = function () { return failing[oidx]; };
-                try {
-                  tmp.tmpNameSync({ dir: failing[iidx] });
-                  assert.fail('expected this to fail');
-                } catch (err) {
-                  assert.ok(err instanceof Error, 'error expected');
-                } finally {
-                  os.tmpdir = origfn;
-                }
-              });
-            }
+        it('must fail on invalid os.tmpdir()', function () {
+          os.tmpdir = function () {
+            return undefined;
+          };
+          try {
+            tmp.tmpNameSync();
+            assert.fail('should have failed');
+          } catch (err) {
+            assert.ok(err instanceof Error);
+          } finally {
+            os.tmpdir = origfn;
           }
         });
-          
-        describe('must not fail on invalid os.tmpdir() and valid opts.dir', function () {
-          // test all non failing permutations for non failing opts.dir and failing osTmpDir
-          for (let oidx = 0; oidx < failing.length; oidx++) {
-            for (let iidx = 0; iidx < nonFailing.length; iidx++) {
-              it(_generateSpecName(nonFailing[iidx], failing[oidx]), function () {
-                os.tmpdir = function () { return failing[oidx]; };
-                try {
-                  tmp.tmpNameSync({ dir: nonFailing[iidx] });
-                } catch (err) {
-                  assert.fail(err);
-                } finally {
-                  os.tmpdir = origfn;
-                }
-              });
-            }
+      });
+      describe('on issue #246', function () {
+        const origfn = os.tmpdir;
+        it('must produce correct name on os.tmpdir() returning path that includes double quotes', function () {
+          const tmpdir = isWindows ? '"C:\\Temp With Spaces"' : '"/tmp with spaces"';
+          os.tmpdir = function () {
+            return tmpdir;
+          };
+          const name = tmp.tmpNameSync();
+          try {
+            assert.ok(name.indexOf('"') === -1);
+            assert.ok(name.startsWith(tmpdir.replace(/["']/g, '')));
+          } finally {
+            os.tmpdir = origfn;
           }
         });
-
-        describe('must not fail on valid os.tmpdir() and invalid opts.dir', function () {
-          // test all non failing permutations for failing opts.dir and non failing osTmpDir
-          for (let oidx = 0; oidx < nonFailing.length; oidx++) {
-            for (let iidx = 0; iidx < failing.length; iidx++) {
-              it(_generateSpecName(failing[iidx], nonFailing[oidx]), function () {
-                os.tmpdir = function () { return nonFailing[oidx]; };
-                try {
-                  tmp.tmpNameSync({ dir: failing[iidx] });
-                } catch (err) {
-                  assert.fail(err);
-                } finally {
-                  os.tmpdir = origfn;
-                }
-              });
-            }
+        it('must produce correct name on os.tmpdir() returning path that includes single quotes', function () {
+          const tmpdir = isWindows ? '\'C:\\Temp With Spaces\'' : '\'/tmp with spaces\'';
+          os.tmpdir = function () {
+            return tmpdir;
+          };
+          const name = tmp.tmpNameSync();
+          try {
+            assert.ok(name.indexOf('\'') === -1);
+            assert.ok(name.startsWith(tmpdir.replace(/["']/g, '')));
+          } finally {
+            os.tmpdir = origfn;
           }
         });
       });
diff --git a/test/name-test.js b/test/name-test.js
index 7dac189..746dfa0 100644
--- a/test/name-test.js
+++ b/test/name-test.js
@@ -7,6 +7,7 @@ const
   inbandStandardTests = require('./name-inband-standard'),
   tmp = require('../lib/tmp');
 
+const isWindows = os.platform() === 'win32';
 
 describe('tmp', function () {
   describe('#tmpName()', function () {
@@ -48,75 +49,51 @@ describe('tmp', function () {
     describe('when running issue specific inband tests', function () {
       describe('on issue #176', function () {
         const origfn = os.tmpdir;
-
-        function _generateSpecName(optsDir, osTmpDir) {
-          return 'opts.dir = "$1", os.tmpdir() = "$2"'.replace('$1', optsDir).replace('$2', osTmpDir);  
-        }
-
-        const failing = ['', '  ', undefined, null];
-        const nonFailing = ['tmp']; // the origfn cannot be trusted as the os may or may not have a valid tmp dir
-
-        describe('must fail on invalid os.tmpdir() and invalid opts.dir', function () {
-          // test all failing permutations
-          for (let oidx = 0; oidx < failing.length; oidx++) {
-            for (let iidx = 0; iidx < failing.length; iidx++) {
-              it(_generateSpecName(failing[iidx], failing[oidx]), function (done) {
-                os.tmpdir = function () { return failing[oidx]; };
-                tmp.tmpName({ dir: failing[iidx] }, function (err) {
-                  try {
-                    assert.ok(err instanceof Error, 'should have failed');
-                  } catch (err) {
-                    return done(err);
-                  } finally {
-                    os.tmpdir = origfn;
-                  }
-                  done();
-                });
-              });
+        it('must fail on invalid os.tmpdir()', function (done) {
+          os.tmpdir = function () { return undefined; };
+          tmp.tmpName(function (err) {
+            try {
+              assert.ok(err instanceof Error, 'should have failed');
+            } catch (err) {
+              return done(err);
+            } finally {
+              os.tmpdir = origfn;
             }
-          }
+            done();
+          });
         });
-          
-        describe('must not fail on invalid os.tmpdir() and valid opts.dir', function () {
-          // test all non failing permutations for non failing opts.dir and failing osTmpDir
-          for (let oidx = 0; oidx < failing.length; oidx++) {
-            for (let iidx = 0; iidx < nonFailing.length; iidx++) {
-              it(_generateSpecName(nonFailing[iidx], failing[oidx]), function (done) {
-                os.tmpdir = function () { return failing[oidx]; };
-                tmp.tmpName({ dir: nonFailing[iidx] }, function (err) {
-                  try {
-                    assert.ok(err === null || err === undefined, 'should not have failed');
-                  } catch (err) {
-                    return done(err);
-                  } finally {
-                    os.tmpdir = origfn;
-                  }
-                  done();
-                });
-              });
+      });
+      describe('on issue #246', function () {
+        const origfn = os.tmpdir;
+        it('must produce correct name on os.tmpdir() returning path that includes double quotes', function (done) {
+          const tmpdir = isWindows ? '"C:\\Temp With Spaces"' : '"/tmp with spaces"';
+          os.tmpdir = function () { return tmpdir; };
+          tmp.tmpName(function (err, name) {
+            try {
+              assert.ok(name.indexOf('"') === -1);
+              assert.ok(name.startsWith(tmpdir.replace(/["']/g, '')));
+            } catch (err) {
+              return done(err);
+            } finally {
+              os.tmpdir = origfn;
             }
-          }
+            done();
+          });
         });
-
-        describe('must not fail on valid os.tmpdir() and invalid opts.dir', function () {
-          // test all non failing permutations for failing opts.dir and non failing osTmpDir
-          for (let oidx = 0; oidx < nonFailing.length; oidx++) {
-            for (let iidx = 0; iidx < failing.length; iidx++) {
-              it(_generateSpecName(failing[iidx], nonFailing[oidx]), function (done) {
-                os.tmpdir = function () { return nonFailing[oidx]; };
-                tmp.tmpName({ dir: failing[iidx] }, function (err) {
-                  try {
-                    assert.ok(err === null || err === undefined, 'should not have failed');
-                  } catch (err) {
-                    return done(err);
-                  } finally {
-                    os.tmpdir = origfn;
-                  }
-                  done();
-                });
-              });
+        it('must produce correct name on os.tmpdir() returning path that includes single quotes', function (done) {
+          const tmpdir = isWindows ? '\'C:\\Temp With Spaces\'' : '\'/tmp with spaces\'';
+          os.tmpdir = function () { return tmpdir; };
+          tmp.tmpName(function (err, name) {
+            try {
+              assert.ok(name.indexOf('\'') === -1);
+              assert.ok(name.startsWith(tmpdir.replace(/["']/g, '')));
+            } catch (err) {
+              return done(err);
+            } finally {
+              os.tmpdir = origfn;
             }
-          }
+            done();
+          });
         });
       });
     });
@@ -128,4 +105,3 @@ describe('tmp', function () {
     });
   });
 });
-
diff --git a/test/outband/issue115-sync.js b/test/outband/issue115-sync.js
new file mode 100644
index 0000000..43b261b
--- /dev/null
+++ b/test/outband/issue115-sync.js
@@ -0,0 +1,10 @@
+var fs = require('fs');
+
+module.exports = function (result) {
+  // creates a tmp file and then closes the file descriptor as per issue 115
+  // https://github.com/raszi/node-tmp/issues/115
+  const self = this;
+  fs.closeSync(result.fd);
+  result.removeCallback();
+  self.out(result.name, self.exit);
+};
diff --git a/test/outband/issue115-sync.json b/test/outband/issue115-sync.json
index d1e2f7f..81a8763 100644
--- a/test/outband/issue115-sync.json
+++ b/test/outband/issue115-sync.json
@@ -1,5 +1,5 @@
 {
-  "tc": "issue115",
+  "tc": "issue115-sync",
   "async": false,
   "file": true,
   "options": {},
diff --git a/test/outband/issue121.js b/test/outband/issue121.js
index fa2b706..87f8c28 100644
--- a/test/outband/issue121.js
+++ b/test/outband/issue121.js
@@ -2,6 +2,10 @@
 
 const tmp = require('../../lib/tmp');
 
+process.on('SIGINT', function () {
+  process.exit(0);
+});
+
 process.on('SIGTERM', function () {
   process.exit(0);
 });
diff --git a/test/outband/issue129-sigint.js b/test/outband/issue129-sigint.js
deleted file mode 100644
index 50a0051..0000000
--- a/test/outband/issue129-sigint.js
+++ /dev/null
@@ -1,32 +0,0 @@
-/* eslint-disable no-octal */
-// vim: expandtab:ts=2:sw=2
-
-// addendum to https://github.com/raszi/node-tmp/issues/129 so that with jest sandboxing we do not install our sigint
-// listener multiple times
-module.exports = function () {
-
-  var self = this;
-
-  // simulate an existing SIGINT listener
-  process.addListener('SIGINT', function _tmp$sigint_listener() {
-    self.out('EOK');
-  });
-
-  // now let tmp install its listener safely
-  require('../../lib/tmp');
-
-  var sigintListeners = [];
-
-  var listeners = process.listeners('SIGINT');
-  for (var i = 0; i < listeners.length; i++) {
-    var listener = listeners[i];
-    if (listener.name === '_tmp$sigint_listener') {
-      sigintListeners.push(listener);
-    }
-  }
-
-  if (sigintListeners.length > 1) this.fail('EEXISTS:MULTIPLE: existing SIGINT listener was not removed', this.exit);
-  if (sigintListeners.length != 1) this.fail('ENOAVAIL: no SIGINT listener was installed', this.exit);
-  // tmp will now exit the process as there are no custom user listeners installed
-  sigintListeners[0]();
-};
diff --git a/test/outband/issue129-sigint.json b/test/outband/issue129-sigint.json
deleted file mode 100644
index 967ff91..0000000
--- a/test/outband/issue129-sigint.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
-  "tc": "issue129-sigint"
-}
diff --git a/test/outband/issue129.js b/test/outband/issue129.js
deleted file mode 100644
index 311704e..0000000
--- a/test/outband/issue129.js
+++ /dev/null
@@ -1,76 +0,0 @@
-/* eslint-disable no-octal */
-// vim: expandtab:ts=2:sw=2
-
-// https://github.com/raszi/node-tmp/issues/129
-module.exports = function () {
-  // dup from lib/tmp.js
-  function _is_legacy_listener(listener) {
-    return (listener.name === '_exit' || listener.name === '_uncaughtExceptionThrown')
-      && listener.toString().indexOf('_garbageCollector();') !== -1;
-  }
-
-  function _garbageCollector() {}
-
-  var callState = {
-    newStyleListener : false,
-    legacyExitListener : false,
-    legacyUncaughtListener : false
-  };
-
-  // simulate the new exit listener
-  var listener1 = (function (callState) {
-    return function _tmp$safe_listener() {
-      _garbageCollector();
-      callState.newStyleListener = true;
-    };
-  })(callState);
-
-  // simulate the legacy _exit listener
-  var listener2 = (function (callState) {
-    return function _exit() {
-      _garbageCollector();
-      callState.legacyExitListener = true;
-    };
-  })(callState);
-
-  // simulate the legacy _uncaughtExceptionThrown listener
-  var listener3 = (function (callState) {
-    return function _uncaughtExceptionThrown() {
-      _garbageCollector();
-      callState.legacyUncaughtListener = true;
-    };
-  })(callState);
-
-  process.addListener('exit', listener1);
-  process.addListener('exit', listener2);
-  process.addListener('exit', listener3);
-
-  // now let tmp install its listener safely
-  require('../../lib/tmp');
-
-  var legacyExitListener = null;
-  var legacyUncaughtListener = null;
-  var newStyleListeners = [];
-
-  var listeners = process.listeners('exit');
-  for (var i = 0; i < listeners.length; i++) {
-    var listener = listeners[i];
-    // the order here is important
-    if (listener.name === '_tmp$safe_listener') {
-      newStyleListeners.push(listener);
-    }
-    else if (_is_legacy_listener(listener)) {
-      if (listener.name === '_uncaughtExceptionThrown') legacyUncaughtListener = listener;
-      else legacyExitListener = listener;
-    }
-  }
-
-  if (legacyExitListener) this.fail('EEXISTS:LEGACY:EXIT existing legacy exit listener was not removed', this.exit);
-  if (legacyUncaughtListener) this.fail('EEXISTS:LEGACY:UNCAUGHT existing legacy uncaught exception thrown listener was not removed', this.exit);
-  if (newStyleListeners.length > 1) this.fail('EEXISTS:NEWSTYLE: existing new style listener was not removed', this.exit);
-  newStyleListeners[0]();
-  if (!callState.legacyExitListener) this.fail('ENOAVAIL:LEGACY:EXIT existing legacy exit listener was not called', this.exit);
-  if (callState.legacyUncaughtListener) this.fail('EAVAIL:LEGACY:UNCAUGHT existing legacy uncaught exception thrown listener should not have been called', this.exit);
-  if (!callState.newStyleListener) this.fail('ENOAVAIL:NEWSTYLE: existing new style listener was not called', this.exit);
-  this.out('EOK', this.exit);
-};
diff --git a/test/outband/issue129.json b/test/outband/issue129.json
deleted file mode 100644
index 3d7794c..0000000
--- a/test/outband/issue129.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
-  "tc": "issue129"
-}
diff --git a/test/outband/unlink.js b/test/outband/unlink.js
index 83efe58..ad44fb6 100644
--- a/test/outband/unlink.js
+++ b/test/outband/unlink.js
@@ -3,6 +3,8 @@ const fs = require('fs');
 module.exports = function (result) {
   const stat = fs.statSync(result.name);
   if (stat.isFile()) {
+    // TODO must also close the file, otherwise the file will be closed during garbage collection, which we do not want
+    // TODO #241 get rid of the open file descriptor
     fs.unlinkSync(result.name);
   } else {
     fs.rmdirSync(result.name);
diff --git a/test/outband/unsafe.js b/test/outband/unsafe.js
index a4ed7e0..25c6092 100644
--- a/test/outband/unsafe.js
+++ b/test/outband/unsafe.js
@@ -15,7 +15,7 @@ module.exports = function (result) {
   // symlink that should be removed but the contents should be preserved.
   // Skip on Windows because symlinks require elevated privileges (instead just
   // create the file)
-  if (process.platform == 'win32') {
+  if (process.platform === 'win32') {
     fs.writeFileSync(symlinkTarget);
   } else {
     fs.symlinkSync(symlinkSource, symlinkTarget, 'dir');
@@ -23,4 +23,3 @@ module.exports = function (result) {
 
   this.out(result.name);
 };
-
diff --git a/test/setup-sigint-listener.js b/test/setup-sigint-listener.js
new file mode 100644
index 0000000..5d8a228
--- /dev/null
+++ b/test/setup-sigint-listener.js
@@ -0,0 +1,2 @@
+// make sure that all garbage gets collected on SIGINT
+process.on('SIGINT', process.exit);
diff --git a/test/spawn-generic.js b/test/spawn-generic.js
index d557db0..f433f6d 100644
--- a/test/spawn-generic.js
+++ b/test/spawn-generic.js
@@ -14,6 +14,10 @@ var fnUnderTest = null;
 if (config.async) fnUnderTest = (config.file) ? tmp.file : tmp.dir;
 else fnUnderTest = (config.file) ? tmp.fileSync : tmp.dirSync;
 
+// make sure that we have a SIGINT handler so CTRL-C the test suite
+// will not leave anything behing
+process.on('SIGINT', process.exit);
+
 // do we test against tmp doing a graceful cleanup?
 if (config.graceful) tmp.setGracefulCleanup();
 
diff --git a/test/template-sync-test.js b/test/template-sync-test.js
index a0e7b39..0a96054 100644
--- a/test/template-sync-test.js
+++ b/test/template-sync-test.js
@@ -11,7 +11,7 @@ describe('tmp', function () {
       try {
         tmp.dirSync({template:'invalid'});
       } catch (err) {
-        assert.equal(err.message, 'Invalid template provided', 'should have thrown the expected error');
+        assert.equal(err.message, 'Invalid template, found "invalid".', 'should have thrown the expected error');
       }
     });
   });
@@ -21,7 +21,7 @@ describe('tmp', function () {
       try {
         tmp.fileSync({template:'invalid'});
       } catch (err) {
-        assert.equal(err.message, 'Invalid template provided', 'should have thrown the expected error');
+        assert.equal(err.message, 'Invalid template, found "invalid".', 'should have thrown the expected error');
       }
     });
   });
diff --git a/test/template-test.js b/test/template-test.js
index 339f51a..ed31f7e 100644
--- a/test/template-test.js
+++ b/test/template-test.js
@@ -11,9 +11,9 @@ describe('tmp', function () {
       tmp.dir({template:'invalid'}, function (err) {
         if (!err) return done(new Error('err expected'));
         try {
-          assert.equal(err.message, 'Invalid template provided', 'should have thrown the expected error');
+          assert.equal(err.message, 'Invalid template, found "invalid".', 'should have thrown the expected error');
         } catch (err2) {
-          done(err);
+          return done(err2);
         }
         done();
       });
@@ -25,9 +25,9 @@ describe('tmp', function () {
       tmp.file({template:'invalid'}, function (err) {
         if (!err) return done(new Error('err expected'));
         try {
-          assert.equal(err.message, 'Invalid template provided', 'should have thrown the expected error');
+          assert.equal(err.message, 'Invalid template, found "invalid".', 'should have thrown the expected error');
         } catch (err2) {
-          done(err);
+          return done(err2);
         }
         done();
       });