Browse Source

fs: add O_EXCL support, exclusive open file

v0.7.4-release
Ben Noordhuis 13 years ago
parent
commit
279e7e7341
  1. 12
      doc/api/fs.markdown
  2. 50
      lib/fs.js
  3. 12
      test/simple/test-fs-open-flags.js

12
doc/api/fs.markdown

@ -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).

50
lib/fs.js

@ -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')) {
throw errnoException('ENOSYS', 'fs.open(O_EXCL)');
}
switch (flag) {
case 'r' : return O_RDONLY;
case 'r+' : return O_RDWR;
case 'w': case 'w' : return O_TRUNC | O_CREAT | O_WRONLY;
return constants.O_CREAT | constants.O_TRUNC | constants.O_WRONLY; case 'wx' : // fall through
case 'xw' : return O_TRUNC | O_CREAT | O_WRONLY | O_EXCL;
case 'w+': case 'w+' : return O_TRUNC | O_CREAT | O_RDWR;
return constants.O_CREAT | constants.O_TRUNC | constants.O_RDWR; case 'wx+': // fall through
case 'xw+': return O_TRUNC | O_CREAT | O_RDWR | O_EXCL;
case 'a': case 'a' : return O_APPEND | O_CREAT | O_WRONLY;
return constants.O_APPEND | constants.O_CREAT | constants.O_WRONLY; case 'ax' : // fall through
case 'xa' : return O_APPEND | O_CREAT | O_WRONLY | O_EXCL;
case 'a+': case 'a+' : return O_APPEND | O_CREAT | O_RDWR;
return constants.O_APPEND | constants.O_CREAT | constants.O_RDWR; case 'ax+': // fall through
case 'xa+': return O_APPEND | O_CREAT | O_RDWR | O_EXCL;
}
default:
throw new Error('Unknown file open flag: ' + flag); 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

12
test/simple/test-fs-open-flags.js

@ -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); });
}); });

Loading…
Cancel
Save