Skip to content

Commit

Permalink
Adding support for Buffer objects in "fs" methods.
Browse files Browse the repository at this point in the history
fs.writeFile(), fs.appendFile() and friends may accept an instance of
Buffer as an argument.

Also, fs.readFile() and friends now return an instance of Buffer instead of
Byte-string when encoding is not provided.

Added Buffer encoding for fs.readdir(), fs.realpath() and friends.
  • Loading branch information
xeioex committed Sep 28, 2020
1 parent 5f7dc4f commit 7fd2166
Show file tree
Hide file tree
Showing 11 changed files with 692 additions and 525 deletions.
489 changes: 223 additions & 266 deletions src/njs_fs.c

Large diffs are not rendered by default.

109 changes: 55 additions & 54 deletions src/test/njs_unit_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -17013,145 +17013,146 @@ static njs_unit_test_t njs_test[] =
/* require('fs').readFile() */

{ njs_str("var fs = require('fs');"
"fs.readFile()"),
njs_str("TypeError: \"path\" must be a string") },
"fs.readFile()"),
njs_str("TypeError: \"path\" must be a string or Buffer") },

{ njs_str("var fs = require('fs');"
"fs.readFile('/njs_unknown_path')"),
"var path = Buffer.from('/broken'); path[3] = 0;"
"fs.readFile(path)"),
njs_str("TypeError: \"path\" must be a Buffer without null bytes") },

{ njs_str("var fs = require('fs');"
"fs.readFile('/njs_unknown_path')"),
njs_str("TypeError: \"callback\" must be a function") },

{ njs_str("var fs = require('fs');"
"fs.readFile('/njs_unknown_path', 'utf8')"),
"fs.readFile('/njs_unknown_path', 'utf8')"),
njs_str("TypeError: \"callback\" must be a function") },

{ njs_str("var fs = require('fs');"
"fs.readFile('/njs_unknown_path', {flag:'xx'})"),
"fs.readFile('/njs_unknown_path', {flag:'xx'})"),
njs_str("TypeError: \"callback\" must be a function") },

{ njs_str("var fs = require('fs');"
"fs.readFile('/njs_unknown_path', {flag:'xx'}, 1)"),
"fs.readFile('/njs_unknown_path', {flag:'xx'}, 1)"),
njs_str("TypeError: \"callback\" must be a function") },

{ njs_str("var fs = require('fs');"
"fs.readFile('/njs_unknown_path', {flag:'xx'}, function () {})"),
"fs.readFile('/njs_unknown_path', {flag:'xx'}, function () {})"),
njs_str("TypeError: Unknown file open flags: \"xx\"") },

{ njs_str("var fs = require('fs');"
"fs.readFile('/njs_unknown_path', {encoding:'ascii'}, function () {})"),
njs_str("TypeError: Unknown encoding: \"ascii\"") },
"fs.readFile('/njs_unknown_path', {encoding:'ascii'}, function () {})"),
njs_str("TypeError: \"ascii\" encoding is not supported") },

{ njs_str("var fs = require('fs');"
"fs.readFile('/njs_unknown_path', 'ascii', function () {})"),
njs_str("TypeError: Unknown encoding: \"ascii\"") },
"fs.readFile('/njs_unknown_path', 'ascii', function () {})"),
njs_str("TypeError: \"ascii\" encoding is not supported") },

/* require('fs').readFileSync() */

{ njs_str("var fs = require('fs');"
"fs.readFileSync()"),
njs_str("TypeError: \"path\" must be a string") },
"fs.readFileSync()"),
njs_str("TypeError: \"path\" must be a string or Buffer") },

{ njs_str("var fs = require('fs');"
"fs.readFileSync({})"),
njs_str("TypeError: \"path\" must be a string") },
"fs.readFileSync({})"),
njs_str("TypeError: \"path\" must be a string or Buffer") },

{ njs_str("var fs = require('fs');"
"fs.readFileSync('/njs_unknown_path', {flag:'xx'})"),
"fs.readFileSync('/njs_unknown_path', {flag:'xx'})"),
njs_str("TypeError: Unknown file open flags: \"xx\"") },

{ njs_str("var fs = require('fs');"
"fs.readFileSync('/njs_unknown_path', {encoding:'ascii'})"),
njs_str("TypeError: Unknown encoding: \"ascii\"") },
"fs.readFileSync(Buffer.from('/njs_unknown_path'), {encoding:'ascii'})"),
njs_str("TypeError: \"ascii\" encoding is not supported") },

{ njs_str("var fs = require('fs');"
"fs.readFileSync('/njs_unknown_path', 'ascii')"),
njs_str("TypeError: Unknown encoding: \"ascii\"") },
"fs.readFileSync('/njs_unknown_path', 'ascii')"),
njs_str("TypeError: \"ascii\" encoding is not supported") },

{ njs_str("var fs = require('fs');"
"fs.readFileSync('/njs_unknown_path', true)"),
"fs.readFileSync('/njs_unknown_path', true)"),
njs_str("TypeError: Unknown options type: \"boolean\" (a string or object required)") },


/* require('fs').writeFile() */

{ njs_str("var fs = require('fs');"
"fs.writeFile()"),
njs_str("TypeError: \"path\" must be a string") },
"fs.writeFile()"),
njs_str("TypeError: \"path\" must be a string or Buffer") },

{ njs_str("var fs = require('fs');"
"fs.writeFile({}, '', function () {})"),
njs_str("TypeError: \"path\" must be a string") },
"fs.writeFile({}, '', function () {})"),
njs_str("TypeError: \"path\" must be a string or Buffer") },

{ njs_str("var fs = require('fs');"
"fs.writeFile('/njs_unknown_path')"),
njs_str("TypeError: \"data\" must be a string") },
"fs.writeFile('/njs_unknown_path')"),
njs_str("TypeError: \"callback\" must be a function") },

{ njs_str("var fs = require('fs');"
"fs.writeFile('/njs_unknown_path', '')"),
"fs.writeFile('/njs_unknown_path', '')"),
njs_str("TypeError: \"callback\" must be a function") },

{ njs_str("var fs = require('fs');"
"fs.writeFile('/njs_unknown_path', '', undefined)"),
"fs.writeFile('/njs_unknown_path', '', undefined)"),
njs_str("TypeError: \"callback\" must be a function") },

{ njs_str("var fs = require('fs');"
"fs.writeFile('/njs_unknown_path', '', 'utf8')"),
"fs.writeFile('/njs_unknown_path', '', 'utf8')"),
njs_str("TypeError: \"callback\" must be a function") },

{ njs_str("var fs = require('fs');"
"fs.writeFile('/njs_unknown_path', '', {flag:'xx'}, function () {})"),
"fs.writeFile('/njs_unknown_path', '', {flag:'xx'}, function () {})"),
njs_str("TypeError: Unknown file open flags: \"xx\"") },

{ njs_str("var fs = require('fs');"
"fs.writeFile('/njs_unknown_path', '', {encoding:'ascii'}, function () {})"),
njs_str("TypeError: Unknown encoding: \"ascii\"") },
"fs.writeFile('/njs_unknown_path', '', {encoding:'ascii'}, function () {})"),
njs_str("TypeError: \"ascii\" encoding is not supported") },

{ njs_str("var fs = require('fs');"
"fs.writeFile('/njs_unknown_path', '', 'ascii', function () {})"),
njs_str("TypeError: Unknown encoding: \"ascii\"") },
"fs.writeFile('/njs_unknown_path', '', 'ascii', function () {})"),
njs_str("TypeError: \"ascii\" encoding is not supported") },

{ njs_str("var fs = require('fs');"
"fs.writeFile('/njs_unknown_path', '', true, function () {})"),
"fs.writeFile('/njs_unknown_path', '', true, function () {})"),
njs_str("TypeError: Unknown options type: \"boolean\" (a string or object required)") },

/* require('fs').writeFileSync() */

{ njs_str("var fs = require('fs');"
"fs.writeFileSync()"),
njs_str("TypeError: \"path\" must be a string") },

{ njs_str("var fs = require('fs');"
"fs.writeFileSync('/njs_unknown_path')"),
njs_str("TypeError: \"data\" must be a string") },
"fs.writeFileSync()"),
njs_str("TypeError: \"path\" must be a string or Buffer") },

{ njs_str("var fs = require('fs');"
"fs.writeFileSync({}, '')"),
njs_str("TypeError: \"path\" must be a string") },
"fs.writeFileSync({}, '')"),
njs_str("TypeError: \"path\" must be a string or Buffer") },

{ njs_str("var fs = require('fs');"
"fs.writeFileSync('/njs_unknown_path', '', {flag:'xx'})"),
"fs.writeFileSync('/njs_unknown_path', '', {flag:'xx'})"),
njs_str("TypeError: Unknown file open flags: \"xx\"") },

{ njs_str("var fs = require('fs');"
"fs.writeFileSync('/njs_unknown_path', '', {encoding:'ascii'})"),
njs_str("TypeError: Unknown encoding: \"ascii\"") },
"fs.writeFileSync('/njs_unknown_path', '', {encoding:'ascii'})"),
njs_str("TypeError: \"ascii\" encoding is not supported") },

{ njs_str("var fs = require('fs');"
"fs.writeFileSync('/njs_unknown_path', '', 'ascii')"),
njs_str("TypeError: Unknown encoding: \"ascii\"") },
"fs.writeFileSync('/njs_unknown_path', '', 'ascii')"),
njs_str("TypeError: \"ascii\" encoding is not supported") },

{ njs_str("var fs = require('fs');"
"fs.writeFileSync('/njs_unknown_path', '', true)"),
"fs.writeFileSync('/njs_unknown_path', '', true)"),
njs_str("TypeError: Unknown options type: \"boolean\" (a string or object required)") },

/* require('fs').renameSync() */

{ njs_str("var fs = require('fs');"
"fs.renameSync()"),
njs_str("TypeError: \"oldPath\" must be a string") },
njs_str("TypeError: \"oldPath\" must be a string or Buffer") },

{ njs_str("var fs = require('fs');"
"fs.renameSync('/njs_unknown_path')"),
njs_str("TypeError: \"newPath\" must be a string") },
njs_str("TypeError: \"newPath\" must be a string or Buffer") },

{ njs_str("var fs = require('fs');"
"[undefined, null, false, NaN, Symbol(), {}, Object('/njs_unknown_path')]"
Expand All @@ -17171,7 +17172,7 @@ static njs_unit_test_t njs_test[] =

{ njs_str("var fs = require('fs');"
"fs.access()"),
njs_str("TypeError: \"path\" must be a string") },
njs_str("TypeError: \"path\" must be a string or Buffer") },

{ njs_str("var fs = require('fs');"
"fs.access('/njs_unknown_path')"),
Expand All @@ -17189,7 +17190,7 @@ static njs_unit_test_t njs_test[] =

{ njs_str("var fs = require('fs');"
"fs.accessSync()"),
njs_str("TypeError: \"path\" must be a string") },
njs_str("TypeError: \"path\" must be a string or Buffer") },

{ njs_str("var fs = require('fs');"
"fs.accessSync('/njs_unknown_path', 'fail')"),
Expand Down
61 changes: 61 additions & 0 deletions test/js/fs_appendFile.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
var fs = require('fs');
var fname = './build/test/fs_appendFile';

var argv = process.argv.slice(2);

var data = (() => {
var value = argv[0];
var type = argv[1];
var offset = argv[2] ? parseInt(argv[2]) : 0;

switch (type) {
case 'Buffer':
return Buffer.from(Buffer.from(value).buffer, offset);
case 'DataView':
return new DataView(Buffer.from(value).buffer, offset);
case 'Object':
return {toString(){return value}};
case 'String':
return String(value);
case 'Symbol':
return Symbol(value);
case 'Uint8Array':
return new Uint8Array(Buffer.from(value).buffer, offset);
default:
throw new Error(`Unknown data type:${type}`);
}
})();

var options = (() => {
var encoding = argv[2];
var mode = argv[3] ? parseInt(argv[3].slice(2), 8) : 0;

if (encoding && mode) {
return {encoding, mode};

} else if (encoding) {
return encoding;
}

return undefined;
})();

try { fs.unlinkSync(fname); } catch (e) {}

function done(e) {
if (e) {throw e};
var data = fs.readFileSync(fname);
console.log(String(data));
}

function append(cb) {
if (options) {
var path = Buffer.from(`@${fname}`).slice(1);
fs.appendFile(path, data, options, cb);

} else {
fs.appendFile(fname, data, cb);
}
}

append((e) => {if (e) {throw e}; append(done);})
59 changes: 59 additions & 0 deletions test/js/fs_appendFileSync.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
var fs = require('fs');
var fname = './build/test/fs_appendFileSync';

var argv = process.argv.slice(2);

var data = (() => {
var value = argv[0];
var type = argv[1];
var offset = argv[2] ? parseInt(argv[2]) : 0;

switch (type) {
case 'Buffer':
return Buffer.from(Buffer.from(value).buffer, offset);
case 'DataView':
return new DataView(Buffer.from(value).buffer, offset);
case 'Object':
return {toString(){return value}};
case 'String':
return String(value);
case 'Symbol':
return Symbol(value);
case 'Uint8Array':
return new Uint8Array(Buffer.from(value).buffer, offset);
default:
throw new Error(`Unknown data type:${type}`);
}
})();

var options = (() => {
var encoding = argv[2];
var mode = argv[3] ? parseInt(argv[3].slice(2), 8) : 0;

if (encoding && mode) {
return {encoding, mode};

} else if (encoding) {
return encoding;
}

return undefined;
})();

function append() {
if (options) {
var path = Buffer.from(`@${fname}`).slice(1);
fs.appendFileSync(path, data, options);

} else {
fs.appendFileSync(fname, data);
}
}

try { fs.unlinkSync(fname); } catch (e) {}

append();
append();

var ret = fs.readFileSync(fname);
console.log(String(ret));
5 changes: 0 additions & 5 deletions test/js/fs_promises_001.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,6 @@ Promise.resolve()
} catch (e) {
console.log('error 2 ok', e instanceof TypeError)
}
try {
return fs.writeFile(fname);
} catch (e) {
console.log('error 3 ok', e instanceof TypeError)
}
})
.then((data) => {
console.log('errors ok');
Expand Down
16 changes: 13 additions & 3 deletions test/js/fs_promises_007.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,16 @@ var testSync = () => new Promise((resolve, reject) => {
throw new Error('fs.readdirSync - error 6');
}

var dir_buffer = fs.readdirSync(dname, {encoding:'buffer'});
if (dir_buffer.length != 3 || !(dir_buffer[0] instanceof Buffer)) {
throw new Error('fs.readdirSync - error 7');
}

var dir_buffer_types = fs.readdirSync(dname, {encoding:'buffer', withFileTypes: true});
if (dir_buffer_types.length != 3 || !(dir_buffer_types[0].name instanceof Buffer)) {
throw new Error('fs.readdirSync - error 8');
}

resolve();

} catch (e) {
Expand Down Expand Up @@ -171,15 +181,15 @@ Promise.resolve()
console.log('test fs.readdirSync');
})
.catch((e) => {
console.log('test fs.readdirSync failed', JSON.stringify(e));
console.log('test fs.readdirSync failed', e, JSON.stringify(e));
})

.then(testCallback)
.then(() => {
console.log('test fs.readdir');
})
.catch((e) => {
console.log('test fs.readdir failed', JSON.stringify(e));
console.log('test fs.readdir failed', e, JSON.stringify(e));
})

.then(() => {
Expand Down Expand Up @@ -227,5 +237,5 @@ Promise.resolve()
console.log('test fsp.readdir');
})
.catch((e) => {
console.log('test fsp.readdir failed', JSON.stringify(e));
console.log('test fsp.readdir failed', e, JSON.stringify(e));
});

0 comments on commit 7fd2166

Please sign in to comment.