fs: add O_EXCL support, exclusive open file

This commit is contained in:
Ben Noordhuis 2012-01-31 01:36:57 +01:00
parent 88b919ea56
commit 279e7e7341
3 changed files with 63 additions and 21 deletions

View File

@ -259,17 +259,29 @@ An exception occurs if the file does not exist.
* `'w'` - Open file for writing. * `'w'` - Open file for writing.
The file is created (if it does not exist) or truncated (if it exists). The file is created (if it does not exist) or truncated (if it exists).
* `'wx'` - Like `'w'` but opens the file in exclusive mode.
* `'w+'` - Open file for reading and writing. * `'w+'` - Open file for reading and writing.
The file is created (if it does not exist) or truncated (if it exists). The file is created (if it does not exist) or truncated (if it exists).
* `'wx+'` - Like `'w+'` but opens the file in exclusive mode.
* `'a'` - Open file for appending. * `'a'` - Open file for appending.
The file is created if it does not exist. The file is created if it does not exist.
* `'ax'` - Like `'a'` but opens the file in exclusive mode.
* `'a+'` - Open file for reading and appending. * `'a+'` - Open file for reading and appending.
The file is created if it does not exist. The file is created if it does not exist.
* `'ax+'` - Like `'a+'` but opens the file in exclusive mode.
`mode` defaults to `0666`. The callback gets two arguments `(err, fd)`. `mode` defaults to `0666`. The callback gets two arguments `(err, fd)`.
Exclusive mode (`O_EXCL`) ensures that `path` is newly created. `fs.open()`
fails if a file by that name already exists. On POSIX systems, symlinks are
not followed. Exclusive mode may or may not work with network file systems.
### fs.openSync(path, flags, [mode]) ### fs.openSync(path, flags, [mode])
Synchronous open(2). Synchronous open(2).

View File

@ -37,6 +37,19 @@ var EventEmitter = require('events').EventEmitter;
var kMinPoolSpace = 128; var kMinPoolSpace = 128;
var kPoolSize = 40 * 1024; var kPoolSize = 40 * 1024;
var O_APPEND = constants.O_APPEND || 0;
var O_CREAT = constants.O_CREAT || 0;
var O_DIRECTORY = constants.O_DIRECTORY || 0;
var O_EXCL = constants.O_EXCL || 0;
var O_NOCTTY = constants.O_NOCTTY || 0;
var O_NOFOLLOW = constants.O_NOFOLLOW || 0;
var O_RDONLY = constants.O_RDONLY || 0;
var O_RDWR = constants.O_RDWR || 0;
var O_SYMLINK = constants.O_SYMLINK || 0;
var O_SYNC = constants.O_SYNC || 0;
var O_TRUNC = constants.O_TRUNC || 0;
var O_WRONLY = constants.O_WRONLY || 0;
fs.Stats = binding.Stats; fs.Stats = binding.Stats;
fs.Stats.prototype._checkModeProperty = function(property) { fs.Stats.prototype._checkModeProperty = function(property) {
@ -178,28 +191,35 @@ function stringToFlags(flag) {
if (typeof flag !== 'string') { if (typeof flag !== 'string') {
return flag; return flag;
} }
switch (flag) {
case 'r':
return constants.O_RDONLY;
case 'r+': // O_EXCL is mandated by POSIX, Windows supports it too.
return constants.O_RDWR; // Let's add a check anyway, just in case.
if (!O_EXCL && ~flag.indexOf('x')) {
case 'w': throw errnoException('ENOSYS', 'fs.open(O_EXCL)');
return constants.O_CREAT | constants.O_TRUNC | constants.O_WRONLY;
case 'w+':
return constants.O_CREAT | constants.O_TRUNC | constants.O_RDWR;
case 'a':
return constants.O_APPEND | constants.O_CREAT | constants.O_WRONLY;
case 'a+':
return constants.O_APPEND | constants.O_CREAT | constants.O_RDWR;
default:
throw new Error('Unknown file open flag: ' + flag);
} }
switch (flag) {
case 'r' : return O_RDONLY;
case 'r+' : return O_RDWR;
case 'w' : return O_TRUNC | O_CREAT | O_WRONLY;
case 'wx' : // fall through
case 'xw' : return O_TRUNC | O_CREAT | O_WRONLY | O_EXCL;
case 'w+' : return O_TRUNC | O_CREAT | O_RDWR;
case 'wx+': // fall through
case 'xw+': return O_TRUNC | O_CREAT | O_RDWR | O_EXCL;
case 'a' : return O_APPEND | O_CREAT | O_WRONLY;
case 'ax' : // fall through
case 'xa' : return O_APPEND | O_CREAT | O_WRONLY | O_EXCL;
case 'a+' : return O_APPEND | O_CREAT | O_RDWR;
case 'ax+': // fall through
case 'xa+': return O_APPEND | O_CREAT | O_RDWR | O_EXCL;
}
throw new Error('Unknown file open flag: ' + flag);
} }
// exported but hidden, only used by test/simple/test-fs-open-flags.js // exported but hidden, only used by test/simple/test-fs-open-flags.js

View File

@ -45,6 +45,16 @@ assert.equal(fs._stringToFlags('w+'), O_TRUNC|O_CREAT|O_RDWR);
assert.equal(fs._stringToFlags('a'), O_APPEND|O_CREAT|O_WRONLY); assert.equal(fs._stringToFlags('a'), O_APPEND|O_CREAT|O_WRONLY);
assert.equal(fs._stringToFlags('a+'), O_APPEND|O_CREAT|O_RDWR); assert.equal(fs._stringToFlags('a+'), O_APPEND|O_CREAT|O_RDWR);
'+ +a +r +w rw wa war raw r++ a++ w++'.split(' ').forEach(function(flags) { assert.equal(fs._stringToFlags('wx'), O_TRUNC|O_CREAT|O_WRONLY|O_EXCL);
assert.equal(fs._stringToFlags('xw'), O_TRUNC|O_CREAT|O_WRONLY|O_EXCL);
assert.equal(fs._stringToFlags('wx+'), O_TRUNC|O_CREAT|O_RDWR|O_EXCL);
assert.equal(fs._stringToFlags('xw+'), O_TRUNC|O_CREAT|O_RDWR|O_EXCL);
assert.equal(fs._stringToFlags('ax'), O_APPEND|O_CREAT|O_WRONLY|O_EXCL);
assert.equal(fs._stringToFlags('xa'), O_APPEND|O_CREAT|O_WRONLY|O_EXCL);
assert.equal(fs._stringToFlags('ax+'), O_APPEND|O_CREAT|O_RDWR|O_EXCL);
assert.equal(fs._stringToFlags('xa+'), O_APPEND|O_CREAT|O_RDWR|O_EXCL);
('+ +a +r +w rw wa war raw r++ a++ w++' +
'x +x x+ rx rx+ wxx wax xwx xxx').split(' ').forEach(function(flags) {
assert.throws(function() { fs._stringToFlags(flags); }); assert.throws(function() { fs._stringToFlags(flags); });
}); });