Skip to content

Commit 0928a52

Browse files
committed
fs: Support mode/flag options to read/append/writeFile
Fix #4841
1 parent 55aa973 commit 0928a52

5 files changed

Lines changed: 142 additions & 59 deletions

File tree

doc/api/fs.markdown

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,12 @@ The callback is given the three arguments, `(err, bytesRead, buffer)`.
410410

411411
Synchronous version of `fs.read`. Returns the number of `bytesRead`.
412412

413-
## fs.readFile(filename, [encoding], [callback])
413+
## fs.readFile(filename, [options], [callback])
414+
415+
* `filename` {String}
416+
* `options` {Object}
417+
* `encoding` {String | Null} default = `null`
418+
* `flag` {String} default = `'r'`
414419

415420
Asynchronously reads the entire contents of a file. Example:
416421

@@ -425,19 +430,28 @@ contents of the file.
425430
If no encoding is specified, then the raw buffer is returned.
426431

427432

428-
## fs.readFileSync(filename, [encoding])
433+
## fs.readFileSync(filename, [options])
429434

430435
Synchronous version of `fs.readFile`. Returns the contents of the `filename`.
431436

432-
If `encoding` is specified then this function returns a string. Otherwise it
433-
returns a buffer.
437+
If the `encoding` option is specified then this function returns a
438+
string. Otherwise it returns a buffer.
439+
434440

441+
## fs.writeFile(filename, data, [options], [callback])
435442

436-
## fs.writeFile(filename, data, [encoding], [callback])
443+
* `filename` {String}
444+
* `data` {String | Buffer}
445+
* `options` {Object}
446+
* `encoding` {String | Null} default = `'utf8'`
447+
* `mode` {Number} default = `438` (aka `0666` in Octal)
448+
* `flag` {String} default = `'w'`
437449

438450
Asynchronously writes data to a file, replacing the file if it already exists.
439-
`data` can be a string or a buffer. The `encoding` argument is ignored if
440-
`data` is a buffer. It defaults to `'utf8'`.
451+
`data` can be a string or a buffer.
452+
453+
The `encoding` option is ignored if `data` is a buffer. It defaults
454+
to `'utf8'`.
441455

442456
Example:
443457

@@ -446,15 +460,21 @@ Example:
446460
console.log('It\'s saved!');
447461
});
448462

449-
## fs.writeFileSync(filename, data, [encoding])
463+
## fs.writeFileSync(filename, data, [options])
450464

451465
The synchronous version of `fs.writeFile`.
452466

453-
## fs.appendFile(filename, data, encoding='utf8', [callback])
467+
## fs.appendFile(filename, data, [options], [callback])
468+
469+
* `filename` {String}
470+
* `data` {String | Buffer}
471+
* `options` {Object}
472+
* `encoding` {String | Null} default = `'utf8'`
473+
* `mode` {Number} default = `438` (aka `0666` in Octal)
474+
* `flag` {String} default = `'a'`
454475

455476
Asynchronously append data to a file, creating the file if it not yet exists.
456-
`data` can be a string or a buffer. The `encoding` argument is ignored if
457-
`data` is a buffer.
477+
`data` can be a string or a buffer.
458478

459479
Example:
460480

@@ -463,7 +483,7 @@ Example:
463483
console.log('The "data to append" was appended to file!');
464484
});
465485

466-
## fs.appendFileSync(filename, data, encoding='utf8')
486+
## fs.appendFileSync(filename, data, [options])
467487

468488
The synchronous version of `fs.appendFile`.
469489

lib/fs.js

Lines changed: 85 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -165,10 +165,20 @@ fs.existsSync = function(path) {
165165
}
166166
};
167167

168-
fs.readFile = function(path, encoding_) {
169-
var encoding = typeof(encoding_) === 'string' ? encoding_ : null;
168+
fs.readFile = function(path, options, callback_) {
170169
var callback = maybeCallback(arguments[arguments.length - 1]);
171170

171+
if (typeof options === 'function' || !options) {
172+
options = { encoding: null, flag: 'r' };
173+
} else if (typeof options === 'string') {
174+
options = { encoding: options, flag: 'r' };
175+
} else if (!options) {
176+
options = { encoding: null, flag: 'r' };
177+
} else if (typeof options !== 'object') {
178+
throw new TypeError('Bad arguments');
179+
}
180+
181+
var encoding = options.encoding;
172182
assertEncoding(encoding);
173183

174184
// first, stat the file, so we know the size.
@@ -178,7 +188,8 @@ fs.readFile = function(path, encoding_) {
178188
var pos = 0;
179189
var fd;
180190

181-
fs.open(path, constants.O_RDONLY, 438 /*=0666*/, function(er, fd_) {
191+
var flag = options.flag || 'r';
192+
fs.open(path, flag, 438 /*=0666*/, function(er, fd_) {
182193
if (er) return callback(er);
183194
fd = fd_;
184195

@@ -243,10 +254,20 @@ fs.readFile = function(path, encoding_) {
243254
}
244255
};
245256

246-
fs.readFileSync = function(path, encoding) {
257+
fs.readFileSync = function(path, options) {
258+
if (!options) {
259+
options = { encoding: null, flag: 'r' };
260+
} else if (typeof options === 'string') {
261+
options = { encoding: options, flag: 'r' };
262+
} else if (typeof options !== 'object') {
263+
throw new TypeError('Bad arguments');
264+
}
265+
266+
var encoding = options.encoding;
247267
assertEncoding(encoding);
248268

249-
var fd = fs.openSync(path, constants.O_RDONLY, 438 /*=0666*/);
269+
var flag = options.flag || 'r';
270+
var fd = fs.openSync(path, flag, 438 /*=0666*/);
250271

251272
var size;
252273
var threw = true;
@@ -888,72 +909,93 @@ function writeAll(fd, buffer, offset, length, position, callback) {
888909
});
889910
}
890911

891-
fs.writeFile = function(path, data, encoding_, callback) {
892-
var encoding = (typeof(encoding_) == 'string' ? encoding_ : 'utf8');
893-
assertEncoding(encoding);
912+
fs.writeFile = function(path, data, options, callback) {
913+
var callback = maybeCallback(arguments[arguments.length - 1]);
894914

895-
callback = maybeCallback(arguments[arguments.length - 1]);
896-
fs.open(path, 'w', 438 /*=0666*/, function(openErr, fd) {
915+
if (typeof options === 'function' || !options) {
916+
options = { encoding: 'utf8', mode: 438 /*=0666*/, flag: 'w' };
917+
} else if (typeof options === 'string') {
918+
options = { encoding: options, mode: 438, flag: 'w' };
919+
} else if (!options) {
920+
options = { encoding: 'utf8', mode: 438 /*=0666*/, flag: 'w' };
921+
} else if (typeof options !== 'object') {
922+
throw new TypeError('Bad arguments');
923+
}
924+
925+
assertEncoding(options.encoding);
926+
927+
var flag = options.flag || 'w';
928+
fs.open(path, options.flag || 'w', options.mode, function(openErr, fd) {
897929
if (openErr) {
898930
if (callback) callback(openErr);
899931
} else {
900932
var buffer = Buffer.isBuffer(data) ? data : new Buffer('' + data,
901-
encoding);
902-
writeAll(fd, buffer, 0, buffer.length, 0, callback);
933+
options.encoding || 'utf8');
934+
var position = /a/.test(flag) ? null : 0;
935+
writeAll(fd, buffer, 0, buffer.length, position, callback);
903936
}
904937
});
905938
};
906939

907-
fs.writeFileSync = function(path, data, encoding) {
908-
assertEncoding(encoding);
940+
fs.writeFileSync = function(path, data, options) {
941+
if (!options) {
942+
options = { encoding: 'utf8', mode: 438 /*=0666*/, flag: 'w' };
943+
} else if (typeof options === 'string') {
944+
options = { encoding: options, mode: 438, flag: 'w' };
945+
} else if (typeof options !== 'object') {
946+
throw new TypeError('Bad arguments');
947+
}
909948

910-
var fd = fs.openSync(path, 'w');
949+
assertEncoding(options.encoding);
950+
951+
var flag = options.flag || 'w';
952+
var fd = fs.openSync(path, flag);
911953
if (!Buffer.isBuffer(data)) {
912-
data = new Buffer('' + data, encoding || 'utf8');
954+
data = new Buffer('' + data, options.encoding || 'utf8');
913955
}
914956
var written = 0;
915957
var length = data.length;
958+
var position = /a/.test(flag) ? null : 0;
916959
try {
917960
while (written < length) {
918-
written += fs.writeSync(fd, data, written, length - written, written);
961+
written += fs.writeSync(fd, data, written, length - written, position);
962+
position += written;
919963
}
920964
} finally {
921965
fs.closeSync(fd);
922966
}
923967
};
924968

925-
fs.appendFile = function(path, data, encoding_, callback) {
926-
var encoding = (typeof(encoding_) == 'string' ? encoding_ : 'utf8');
927-
assertEncoding(encoding);
969+
fs.appendFile = function(path, data, options, callback_) {
970+
var callback = maybeCallback(arguments[arguments.length - 1]);
928971

929-
callback = maybeCallback(arguments[arguments.length - 1]);
972+
if (typeof options === 'function' || !options) {
973+
options = { encoding: 'utf8', mode: 438 /*=0666*/, flag: 'a' };
974+
} else if (typeof options === 'string') {
975+
options = { encoding: options, mode: 438, flag: 'a' };
976+
} else if (!options) {
977+
options = { encoding: 'utf8', mode: 438 /*=0666*/, flag: 'a' };
978+
} else if (typeof options !== 'object') {
979+
throw new TypeError('Bad arguments');
980+
}
930981

931-
fs.open(path, 'a', 438 /*=0666*/, function(err, fd) {
932-
if (err) return callback(err);
933-
var buffer = Buffer.isBuffer(data) ? data : new Buffer('' + data, encoding);
934-
writeAll(fd, buffer, 0, buffer.length, null, callback);
935-
});
982+
if (!options.flag)
983+
options = util._extend({ flag: 'a' }, options);
984+
fs.writeFile(path, data, options, callback);
936985
};
937986

938-
fs.appendFileSync = function(path, data, encoding) {
939-
assertEncoding(encoding);
940-
941-
var fd = fs.openSync(path, 'a');
942-
if (!Buffer.isBuffer(data)) {
943-
data = new Buffer('' + data, encoding || 'utf8');
987+
fs.appendFileSync = function(path, data, options) {
988+
if (!options) {
989+
options = { encoding: 'utf8', mode: 438 /*=0666*/, flag: 'a' };
990+
} else if (typeof options === 'string') {
991+
options = { encoding: options, mode: 438, flag: 'a' };
992+
} else if (typeof options !== 'object') {
993+
throw new TypeError('Bad arguments');
944994
}
945-
var written = 0;
946-
var position = null;
947-
var length = data.length;
995+
if (!options.flag)
996+
options = util._extend({ flag: 'a' }, options);
948997

949-
try {
950-
while (written < length) {
951-
written += fs.writeSync(fd, data, written, length - written, position);
952-
position += written; // XXX not safe with multiple concurrent writers?
953-
}
954-
} finally {
955-
fs.closeSync(fd);
956-
}
998+
fs.writeFileSync(path, data, options);
957999
};
9581000

9591001
function errnoException(errorno, syscall) {

test/simple/test-fs-append-file-sync.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,17 @@ assert.equal(buf.length + currentFileData.length, fileData3.length);
7373

7474
// test that appendFile accepts numbers.
7575
var filename4 = join(common.tmpDir, 'append-sync4.txt');
76-
fs.writeFileSync(filename4, currentFileData);
76+
fs.writeFileSync(filename4, currentFileData, { mode: m });
7777

7878
common.error('appending to ' + filename4);
79-
fs.appendFileSync(filename4, num);
79+
var m = 0600;
80+
fs.appendFileSync(filename4, num, { mode: m });
81+
82+
// windows permissions aren't unix
83+
if (process.platform !== 'win32') {
84+
var st = fs.statSync(filename4);
85+
assert.equal(st.mode & 0700, m);
86+
}
8087

8188
var fileData4 = fs.readFileSync(filename4);
8289

test/simple/test-fs-append-file.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,12 +101,19 @@ fs.writeFileSync(filename4, currentFileData);
101101

102102
common.error('appending to ' + filename4);
103103

104-
fs.appendFile(filename4, n, function(e) {
104+
var m = 0600;
105+
fs.appendFile(filename4, n, { mode: m }, function(e) {
105106
if (e) throw e;
106107

107108
ncallbacks++;
108109
common.error('appended to file4');
109110

111+
// windows permissions aren't unix
112+
if (process.platform !== 'win32') {
113+
var st = fs.statSync(filename4);
114+
assert.equal(st.mode & 0700, m);
115+
}
116+
110117
fs.readFile(filename4, function(e, buffer) {
111118
if (e) throw e;
112119
common.error('file4 read');

test/simple/test-fs-write-file.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,16 @@ fs.writeFile(filename2, buf, function(e) {
7676
var filename3 = join(common.tmpDir, 'test3.txt');
7777
common.error('writing to ' + filename3);
7878

79-
fs.writeFile(filename3, n, function(e) {
79+
var m = 0600;
80+
fs.writeFile(filename3, n, { mode: m }, function(e) {
8081
if (e) throw e;
8182

83+
// windows permissions aren't unix
84+
if (process.platform !== 'win32') {
85+
var st = fs.statSync(filename3);
86+
assert.equal(st.mode & 0700, m);
87+
}
88+
8289
ncallbacks++;
8390
common.error('file3 written');
8491

0 commit comments

Comments
 (0)