Commit bc968401 authored by Ross Gammon's avatar Ross Gammon

New upstream version 0.0.31

parent 7f7b41b5
module.exports = {
"env": {
"node": true
},
"extends": "eslint:recommended",
"rules": {
"indent": [
"error",
2
],
"linebreak-style": [
"error",
"unix"
],
"quotes": [
"error",
"single"
],
"semi": [
"error",
"always"
]
}
};
......@@ -6,3 +6,29 @@ node_js:
- "0.12"
- "4.0"
- "4.1"
- "4.2"
- "4.3"
- "4.4"
- "5.0"
- "5.1"
- "5.2"
- "5.3"
- "5.4"
- "5.5"
- "5.6"
- "5.7"
- "5.8"
- "5.9"
- "5.10"
- "5.11"
- "6.0"
- "6.1"
- "node"
sudo: false
cache:
directories:
- node_modules
before_install:
# Update Node.js modules
- "test ! -d node_modules || npm prune"
- "test ! -d node_modules || npm rebuild"
......@@ -2,7 +2,9 @@
A simple temporary file and directory creator for [node.js.][1]
[![Build Status](https://secure.travis-ci.org/raszi/node-tmp.png?branch=master)](http://travis-ci.org/raszi/node-tmp)
[![Build Status](https://travis-ci.org/raszi/node-tmp.svg?branch=master)](https://travis-ci.org/raszi/node-tmp)
[![Dependencies](https://david-dm.org/raszi/node-tmp.svg)](https://david-dm.org/raszi/node-tmp)
[![npm version](https://badge.fury.io/js/tmp.svg)](https://badge.fury.io/js/tmp)
## About
......@@ -162,6 +164,45 @@ console.log("File: ", tmpobj.name);
console.log("Filedescriptor: ", tmpobj.fd);
```
### Controlling the Descriptor
As a side effect of creating a unique file `tmp` gets a file descriptor that is
returned to the user as the `fd` parameter. The descriptor may be used by the
application and is closed when the `removeCallback` is invoked.
In some use cases the application does not need the descriptor, needs to close it
without removing the file, or needs to remove the file without closing the
descriptor. Two options control how the descriptor is managed:
* `discardDescriptor` - if `true` causes `tmp` to close the descriptor after the file
is created. In this case the `fd` parameter is undefined.
* `detachDescriptor` - if `true` causes `tmp` to return the descriptor in the `fd`
parameter, but it is the application's responsibility to close it when it is no
longer needed.
```javascript
var 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.
});
```
```javascript
var tmp = require('tmp');
tmp.file({ detachDescriptor: true }, function _tempFileCreated(err, path, fd, cleanupCallback) {
if (err) throw err;
cleanupCallback();
// 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.
});
```
### Asynchronous directory creation
Creates a directory with mode `0755`, prefix will be `myTmpDir_`.
......@@ -187,7 +228,7 @@ var tmpobj = tmp.dirSync({ mode: 0750, prefix: 'myTmpDir_' });
console.log("Dir: ", tmpobj.name);
```
### mkstemps like, asynchronously
### mkstemp like, asynchronously
Creates a new temporary directory with mode `0700` and filename like `/tmp/tmp-nk2J1u`.
......@@ -201,7 +242,7 @@ tmp.dir({ template: '/tmp/tmp-XXXXXX' }, function _tempDirCreated(err, path) {
});
```
### mkstemps like, synchronously
### mkstemp like, synchronously
This will behave similarly to the asynchronous version.
......@@ -254,7 +295,7 @@ All options are optional :)
* `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`: [`mkstemps`][3] like filename template, no default
* `template`: [`mkstemp`][3] like filename template, no default
* `dir`: the optional temporary directory, fallbacks to system default (guesses from environment)
* `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`, means delete
......
......@@ -12,12 +12,9 @@
var
fs = require('fs'),
path = require('path'),
os = require('os'),
crypto = require('crypto'),
exists = fs.exists || path.exists,
existsSync = fs.existsSync || path.existsSync,
tmpDir = require('os-tmpdir'),
_c = require('constants');
_c = process.binding('constants');
/**
......@@ -34,7 +31,10 @@ var
DEFAULT_TRIES = 3,
CREATE_FLAGS = _c.O_CREAT | _c.O_EXCL | _c.O_RDWR,
CREATE_FLAGS = (_c.O_CREAT || _c.fs.O_CREAT) | (_c.O_EXCL || _c.fs.O_EXCL) | (_c.O_RDWR || _c.fs.O_RDWR),
EBADF = _c.EBADF || _c.os.errno.EBADF,
ENOENT = _c.ENOENT || _c.os.errno.ENOENT,
DIR_MODE = 448 /* 0700 */,
FILE_MODE = 384 /* 0600 */,
......@@ -95,8 +95,8 @@ function _isUndefined(obj) {
function _parseArguments(options, callback) {
if (typeof options == 'function') {
var
tmp = options;
options = callback || {};
tmp = options,
options = callback || {},
callback = tmp;
} else if (typeof options == 'undefined') {
options = {};
......@@ -157,8 +157,8 @@ function _getTmpName(options, callback) {
var name = _generateTmpName(opts);
// check whether the path exists then retry if needed
exists(name, function _pathExists(pathExists) {
if (pathExists) {
fs.stat(name, function (err) {
if (!err) {
if (tries-- > 0) return _getUniqueName();
return cb(new Error('Could not get a unique tmp filename, max tries reached ' + name));
......@@ -190,7 +190,9 @@ function _getTmpNameSync(options) {
do {
var name = _generateTmpName(opts);
if (!existsSync(name)) {
try {
fs.statSync(name);
} catch (e) {
return name;
}
} while (tries-- > 0);
......@@ -211,7 +213,7 @@ function _createTmpFile(options, callback) {
opts = args[0],
cb = args[1];
opts.postfix = (_isUndefined(opts.postfix)) ? '.tmp' : opts.postfix;
opts.postfix = (_isUndefined(opts.postfix)) ? '.tmp' : opts.postfix;
// gets a temporary filename
_getTmpName(opts, function _tmpNameCreated(err, name) {
......@@ -221,6 +223,26 @@ function _createTmpFile(options, callback) {
fs.open(name, CREATE_FLAGS, opts.mode || FILE_MODE, function _fileCreated(err, fd) {
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));
});
}
if (opts.detachDescriptor) {
return cb(null, name, fd, _prepareTmpFileRemoveCallback(name, -1, opts));
}
cb(null, name, fd, _prepareTmpFileRemoveCallback(name, fd, opts));
});
});
......@@ -238,7 +260,7 @@ function _createTmpFileSync(options) {
args = _parseArguments(options),
opts = args[0];
opts.postfix = opts.postfix || '.tmp';
opts.postfix = opts.postfix || '.tmp';
var name = _getTmpNameSync(opts);
var fd = fs.openSync(name, CREATE_FLAGS, opts.mode || FILE_MODE);
......@@ -274,7 +296,7 @@ function _rmdirRecursiveSync(root) {
if (!deferred) {
deferred = true;
dirs.push(dir);
}
}
dirs.push(file);
} else {
fs.unlinkSync(file);
......@@ -346,13 +368,15 @@ function _createTmpDirSync(options) {
function _prepareTmpFileRemoveCallback(name, fd, opts) {
var removeCallback = _prepareRemoveCallback(function _removeCallback(fdPath) {
try {
fs.closeSync(fdPath[0]);
if (0 <= fdPath[0]) {
fs.closeSync(fdPath[0]);
}
}
catch (e) {
// under some node/windows related circumstances, a temporary file
// 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 != -_c.EBADF && e.errno != -c.ENOENT) {
if (e.errno != -EBADF && e.errno != -ENOENT) {
// reraise any unanticipated error
throw e;
}
......@@ -397,16 +421,17 @@ function _prepareTmpDirRemoveCallback(name, opts) {
function _prepareRemoveCallback(removeFunction, arg) {
var called = false;
return function _cleanupCallback() {
if (called) return;
return function _cleanupCallback(next) {
if (!called) {
var index = _removeObjects.indexOf(_cleanupCallback);
if (index >= 0) {
_removeObjects.splice(index, 1);
}
var index = _removeObjects.indexOf(removeFunction);
if (index >= 0) {
_removeObjects.splice(index, 1);
called = true;
removeFunction(arg);
}
called = true;
removeFunction(arg);
if (next) next(null);
};
}
......@@ -420,9 +445,11 @@ function _garbageCollector() {
return;
}
for (var i = 0, length = _removeObjects.length; i < length; i++) {
// the function being called removes itself from _removeObjects,
// loop until _removeObjects is empty
while (_removeObjects.length) {
try {
_removeObjects[i].call(null);
_removeObjects[0].call(null);
} catch (e) {
// already removed?
}
......
{
"name": "tmp",
"version": "0.0.28",
"name": "tmp",
"version": "0.0.31",
"description": "Temporary file and directory creator",
"author": "KARASZI István <github@spam.raszi.hu> (http://raszi.hu/)",
"homepage": "http://github.com/raszi/node-tmp",
"keywords": [ "temporary", "tmp", "temp", "tempdir", "tempfile", "tmpdir", "tmpfile" ],
"author": "KARASZI István <github@spam.raszi.hu> (http://raszi.hu/)",
"keywords": [
"temporary",
"tmp",
"temp",
"tempdir",
"tempfile",
"tmpdir",
"tmpfile"
],
"license": "MIT",
"repository": {
"type": "git",
"url": "git://github.com/raszi/node-tmp.git"
},
"repository": "raszi/node-tmp",
"homepage": "http://github.com/raszi/node-tmp",
"bugs": {
"url": "http://github.com/raszi/node-tmp/issues"
},
"main": "lib/tmp.js",
"scripts": {
"test": "vows test/*-test.js"
},
"engines": {
"node": ">=0.4.0"
},
"dependencies": {
"os-tmpdir": "~1.0.1"
},
"devDependencies": {
"vows": "~0.7.0"
},
"main": "lib/tmp.js",
"files": ["lib/"],
"scripts": {
"test": "vows test/*-test.js"
}
}
......@@ -86,6 +86,10 @@ function _testGracefulSync(type, graceful, cb) {
_spawnTestWithoutError('graceful-sync.js', [ type, graceful ], cb);
}
function _assertNoDescriptor(err, name, fd) {
assert.strictEqual(fd, undefined);
}
function _assertName(err, name) {
assert.isString(name);
assert.isNotZero(name.length, 'an empty string is not a valid name');
......@@ -141,6 +145,7 @@ module.exports.testGraceful = _testGraceful;
module.exports.testGracefulSync = _testGracefulSync;
module.exports.assertName = _assertName;
module.exports.assertNameSync = _assertNameSync;
module.exports.assertNoDescriptor = _assertNoDescriptor;
module.exports.testName = _testName;
module.exports.testNameSync = _testNameSync;
module.exports.testUnsafeCleanup = _testUnsafeCleanup;
......
......@@ -32,6 +32,35 @@ function _testFile(mode, fdTest) {
};
}
function _testFileNoDescriptor(mode) {
return function _testFileNoDescriptor(err, name, fd) {
assert.ok(existsSync(name), 'should exist');
var stat = fs.statSync(name);
assert.equal(stat.size, 0, 'should have zero size');
assert.ok(stat.isFile(), 'should be a file');
Test.testStat(stat, mode);
assert.strictEqual(fd, undefined);
};
}
function _testFileAfterDetachRemove(mode) {
return function _testFileAfterDetachRemove(err, name, fd) {
assert.ok(!existsSync(name), 'File should be removed');
var fstat = fs.fstatSync(fd);
assert.equal(fstat.size, 0, 'should have zero size');
assert.ok(fstat.isFile(), 'should be a file');
Test.testStat(fstat, mode);
var data = new Buffer('something');
assert.equal(fs.writeSync(fd, data, 0, data.length, 0), data.length, 'should be writable');
assert.ok(!fs.closeSync(fd), 'should not return with error');
};
}
vows.describe('File creation').addBatch({
'when using without parameters': {
topic: function () {
......@@ -93,6 +122,31 @@ vows.describe('File creation').addBatch({
}
},
'when using discardDescriptor': {
topic: function () {
tmp.file({ discardDescriptor: true }, this.callback);
},
'should not return with an error': assert.isNull,
'should return with a name': Test.assertName,
'should not return with a descriptor': Test.assertNoDescriptor,
'should be a file': _testFileNoDescriptor(0100600),
},
'when using detachDescriptor': {
topic: function () {
var cb = this.callback;
tmp.file({ detachDescriptor: true }, function (err, name, fd, removeCallback) {
removeCallback();
return cb(err, name, fd);
});
},
'should not return with an error': assert.isNull,
'should return with a name': Test.assertName,
'should have working descriptor after removeCallback': _testFileAfterDetachRemove(0100600),
},
'when using multiple options': {
topic: function () {
tmp.file({ prefix: 'foo', postfix: 'bar', mode: 0640 }, this.callback);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment