From a2e13b62dce776f7a3de7ad05d466cf24f4e5248 Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Mon, 8 May 2017 22:57:58 -0700 Subject: [PATCH] Properly handle directories as arguments (#713) * fix(cat): do not cat directories Fixes #707 * fix(head): do not let head() read directories Also fixes a typo * fix(sort): do not sort directories Also fixes a typo * fix(tail): do not let tail() read directories Also fixes a typo * fix(uniq): do not let uniq() read directories We also had a test which called sort() instead of uniq(), so we never actually tested the missing-file case. This fixes that as well. This also throws an error for using a directory as output. * fix(pipe): fix breakages with piped commands --- src/cat.js | 2 ++ src/head.js | 13 ++++++++++--- src/sort.js | 13 ++++++++++--- src/tail.js | 13 ++++++++++--- src/uniq.js | 13 ++++++++++++- test/cat.js | 7 +++++++ test/head.js | 11 ++++++++++- test/sort.js | 10 +++++++++- test/tail.js | 10 +++++++++- test/uniq.js | 25 ++++++++++++++++++++++++- 10 files changed, 103 insertions(+), 14 deletions(-) diff --git a/src/cat.js b/src/cat.js index a74a25c..af1ad1d 100644 --- a/src/cat.js +++ b/src/cat.js @@ -30,6 +30,8 @@ function _cat(options, files) { files.forEach(function (file) { if (!fs.existsSync(file)) { common.error('no such file or directory: ' + file); + } else if (fs.statSync(file).isDirectory()) { + common.error(file + ': Is a directory'); } cat += fs.readFileSync(file, 'utf8'); diff --git a/src/head.js b/src/head.js index db5592e..e112e49 100644 --- a/src/head.js +++ b/src/head.js @@ -72,9 +72,16 @@ function _head(options, files) { var shouldAppendNewline = false; files.forEach(function (file) { - if (!fs.existsSync(file) && file !== '-') { - common.error('no such file or directory: ' + file, { continue: true }); - return; + if (file !== '-') { + if (!fs.existsSync(file)) { + common.error('no such file or directory: ' + file, { continue: true }); + return; + } else if (fs.statSync(file).isDirectory()) { + common.error("error reading '" + file + "': Is a directory", { + continue: true, + }); + return; + } } var contents; diff --git a/src/sort.js b/src/sort.js index 041b037..2ebccd7 100644 --- a/src/sort.js +++ b/src/sort.js @@ -69,9 +69,16 @@ function _sort(options, files) { var lines = []; files.forEach(function (file) { - if (!fs.existsSync(file) && file !== '-') { - // exit upon any sort of error - common.error('no such file or directory: ' + file); + if (file !== '-') { + if (!fs.existsSync(file)) { + common.error('no such file or directory: ' + file, { continue: true }); + return; + } else if (fs.statSync(file).isDirectory()) { + common.error('read failed: ' + file + ': Is a directory', { + continue: true, + }); + return; + } } var contents = file === '-' ? pipe : fs.readFileSync(file, 'utf8'); diff --git a/src/tail.js b/src/tail.js index 7ece654..e5a8805 100644 --- a/src/tail.js +++ b/src/tail.js @@ -46,9 +46,16 @@ function _tail(options, files) { var shouldAppendNewline = false; files.forEach(function (file) { - if (!fs.existsSync(file) && file !== '-') { - common.error('no such file or directory: ' + file, { continue: true }); - return; + if (file !== '-') { + if (!fs.existsSync(file)) { + common.error('no such file or directory: ' + file, { continue: true }); + return; + } else if (fs.statSync(file).isDirectory()) { + common.error("error reading '" + file + "': Is a directory", { + continue: true, + }); + return; + } } var contents = file === '-' ? pipe : fs.readFileSync(file, 'utf8'); diff --git a/src/uniq.js b/src/uniq.js index 8f5da00..3012161 100644 --- a/src/uniq.js +++ b/src/uniq.js @@ -40,7 +40,18 @@ function _uniq(options, input, output) { // Check if this is coming from a pipe var pipe = common.readFromPipe(); - if (!input && !pipe) common.error('no input given'); + if (!pipe) { + if (!input) common.error('no input given'); + + if (!fs.existsSync(input)) { + common.error(input + ': No such file or directory'); + } else if (fs.statSync(input).isDirectory()) { + common.error("error reading '" + input + "'"); + } + } + if (output && fs.existsSync(output) && fs.statSync(output).isDirectory()) { + common.error(output + ': Is a directory'); + } var lines = (input ? fs.readFileSync(input, 'utf8') : pipe). trimRight(). diff --git a/test/cat.js b/test/cat.js index 654b304..53bd522 100644 --- a/test/cat.js +++ b/test/cat.js @@ -25,6 +25,13 @@ test('nonexistent file', t => { t.is(result.stderr, 'cat: no such file or directory: /asdfasdf'); }); +test('directory', t => { + const result = shell.cat('resources/cat'); + t.truthy(shell.error()); + t.is(result.code, 1); + t.is(result.stderr, 'cat: resources/cat: Is a directory'); +}); + // // Valids // diff --git a/test/head.js b/test/head.js index 19ee9e4..5d3beb3 100644 --- a/test/head.js +++ b/test/head.js @@ -18,9 +18,18 @@ test('no args', t => { test('file does not exist', t => { t.falsy(fs.existsSync('/asdfasdf')); // sanity check - const result = shell.head('/adsfasdf'); // file does not exist + const result = shell.head('/asdfasdf'); // file does not exist t.truthy(shell.error()); t.is(result.code, 1); + t.is(result.stderr, 'head: no such file or directory: /asdfasdf'); +}); + +test('directory', t => { + t.truthy(fs.statSync('resources/').isDirectory()); // sanity check + const result = shell.head('resources/'); + t.truthy(shell.error()); + t.is(result.code, 1); + t.is(result.stderr, "head: error reading 'resources/': Is a directory"); }); // diff --git a/test/sort.js b/test/sort.js index 23109d2..ecba454 100644 --- a/test/sort.js +++ b/test/sort.js @@ -25,11 +25,19 @@ test('no args', t => { test('file does not exist', t => { t.falsy(fs.existsSync('/asdfasdf')); // sanity check - const result = shell.sort('/adsfasdf'); + const result = shell.sort('/asdfasdf'); t.truthy(shell.error()); t.truthy(result.code); }); +test('directory', t => { + t.truthy(fs.statSync('resources/').isDirectory()); // sanity check + const result = shell.sort('resources/'); + t.truthy(shell.error()); + t.is(result.code, 1); + t.is(result.stderr, 'sort: read failed: resources/: Is a directory'); +}); + // // Valids // diff --git a/test/tail.js b/test/tail.js index 1ec7dd8..8d3eba2 100644 --- a/test/tail.js +++ b/test/tail.js @@ -18,11 +18,19 @@ test('no args', t => { test('file does not exist', t => { t.falsy(fs.existsSync('/asdfasdf')); // sanity check - const result = shell.tail('/adsfasdf'); + const result = shell.tail('/asdfasdf'); t.truthy(shell.error()); t.is(result.code, 1); }); +test('directory', t => { + t.truthy(fs.statSync('resources/').isDirectory()); // sanity check + const result = shell.tail('resources/'); + t.truthy(shell.error()); + t.is(result.code, 1); + t.is(result.stderr, "tail: error reading 'resources/': Is a directory"); +}); + // // Valids // diff --git a/test/uniq.js b/test/uniq.js index ef4fad7..7515225 100644 --- a/test/uniq.js +++ b/test/uniq.js @@ -18,11 +18,34 @@ test('no args', t => { test('file does not exist', t => { t.falsy(fs.existsSync('/asdfasdf')); // sanity check - const result = shell.sort('/adsfasdf'); + const result = shell.uniq('/asdfasdf'); t.truthy(shell.error()); t.truthy(result.code); }); +test('directory', t => { + t.truthy(fs.statSync('resources/').isDirectory()); // sanity check + const result = shell.uniq('resources/'); + t.truthy(shell.error()); + t.is(result.code, 1); + t.is(result.stderr, "uniq: error reading 'resources/'"); +}); + +test('output directory', t => { + t.truthy(fs.statSync('resources/').isDirectory()); // sanity check + const result = shell.uniq('resources/file1.txt', 'resources/'); + t.truthy(shell.error()); + t.is(result.code, 1); + t.is(result.stderr, 'uniq: resources/: Is a directory'); +}); + +test('file does not exist with output directory', t => { + t.falsy(fs.existsSync('/asdfasdf')); // sanity check + const result = shell.uniq('/asdfasdf', 'resources/'); + t.is(result.code, 1); + t.truthy(shell.error()); +}); + // // Valids //