From e84d327e38d275846b84c0bde353bd2921bfae51 Mon Sep 17 00:00:00 2001 From: isaacs Date: Fri, 24 Jan 2020 12:59:33 -0800 Subject: [PATCH] Handle EROFS errors A EROFS will be raised when trying to write a dir onto a read-only filesystem. However, if the dir already is there, then it should be treated like an EEXIST (since EROFS can be raised by trying to create a dir over a mount point, where the mount point is not read-only, but you still can't just clobber over it). If the dir doesn't already exist, then the EROFS will be accurately reported as the reason why it could not be created. (Copied from 17ee84f2073a262a65e201acedb71e0d20bf9273) --- lib/mkdirp-manual.js | 4 ++-- test/mkdirp-manual.js | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/lib/mkdirp-manual.js b/lib/mkdirp-manual.js index 703b3f5..2eb18cd 100644 --- a/lib/mkdirp-manual.js +++ b/lib/mkdirp-manual.js @@ -16,7 +16,7 @@ const mkdirpManual = (path, opts, made) => { if (er.code === 'ENOENT') return mkdirpManual(parent, opts) .then(made => mkdirpManual(path, opts, made)) - if (er.code !== 'EEXIST') + if (er.code !== 'EEXIST' && er.code !== 'EROFS') throw er return opts.statAsync(path).then(st => { if (st.isDirectory()) @@ -50,7 +50,7 @@ const mkdirpManualSync = (path, opts, made) => { } catch (er) { if (er.code === 'ENOENT') return mkdirpManualSync(path, opts, mkdirpManualSync(parent, opts, made)) - if (er.code !== 'EEXIST') + if (er.code !== 'EEXIST' && er.code !== 'EROFS') throw er try { if (!opts.statSync(path).isDirectory()) diff --git a/test/mkdirp-manual.js b/test/mkdirp-manual.js index c252e21..b19c8d7 100644 --- a/test/mkdirp-manual.js +++ b/test/mkdirp-manual.js @@ -62,6 +62,26 @@ t.test('mkdirpManual / just calls implementation', t => { t.end() }) +t.test('read-only file system, still succeed if dir exists', t => { + const dir = t.testdir({ foo: {} }) + const opt = { + stat, + statAsync, + statSync, + mkdir, + mkdirAsync: () => Promise.reject(Object.assign(new Error('EROFS'), { + code: 'EROFS', + })), + mkdirSync: () => { + throw Object.assign(new Error('EROFS'), { + code: 'EROFS', + }) + }, + } + t.equal(mkdirpManualSync(`${dir}/foo`, opt), undefined) + return mkdirpManual(`${dir}/foo`, opt).then(made => t.equal(made, undefined)) +}) + t.test('recurse and return first dir made', t => { const dir = t.testdir() const opt = {