diff --git a/fs.js b/fs.js index 6f4f44e..01f2e1a 100644 --- a/fs.js +++ b/fs.js @@ -57,13 +57,13 @@ exports.utimesSync = (path, atime, mtime) => { } }; -exports.makeDir = path => makeDir(path, {fs}).catch(error => { +exports.makeDir = (path, options) => makeDir(path, {...options, fs}).catch(error => { throw new CpFileError(`Cannot create directory \`${path}\`: ${error.message}`, error); }); -exports.makeDirSync = path => { +exports.makeDirSync = (path, options) => { try { - makeDir.sync(path, {fs}); + makeDir.sync(path, {...options, fs}); } catch (error) { throw new CpFileError(`Cannot create directory \`${path}\`: ${error.message}`, error); } diff --git a/index.d.ts b/index.d.ts index 6be584e..f0cda7b 100644 --- a/index.d.ts +++ b/index.d.ts @@ -6,6 +6,13 @@ declare namespace cpFile { @default true */ readonly overwrite?: boolean; + + /** + [Permissions](https://en.wikipedia.org/wiki/File-system_permissions#Numeric_notation) for created directories. + + @default 0o777 + */ + readonly directoryMode?: number; } interface ProgressData { diff --git a/index.js b/index.js index 551aa4c..a9d89de 100644 --- a/index.js +++ b/index.js @@ -12,7 +12,7 @@ const cpFileAsync = async (source, destination, options, progressEmitter) => { progressEmitter.size = stat.size; const readStream = await fs.createReadStream(source); - await fs.makeDir(path.dirname(destination)); + await fs.makeDir(path.dirname(destination), {mode: options.directoryMode}); const writeStream = fs.createWriteStream(destination, {flags: options.overwrite ? 'w' : 'wx'}); readStream.on('data', () => { @@ -94,7 +94,7 @@ module.exports.sync = (source, destination, options) => { const stat = fs.statSync(source); checkSourceIsFile(stat, source); - fs.makeDirSync(path.dirname(destination)); + fs.makeDirSync(path.dirname(destination), {mode: options.directoryMode}); const flags = options.overwrite ? null : fsConstants.COPYFILE_EXCL; try { diff --git a/index.test-d.ts b/index.test-d.ts index 40e0a4b..3aca2de 100644 --- a/index.test-d.ts +++ b/index.test-d.ts @@ -1,4 +1,4 @@ -import {expectType} from 'tsd'; +import {expectError, expectType} from 'tsd'; import cpFile = require('.'); import {ProgressEmitter, ProgressData} from '.'; @@ -8,6 +8,16 @@ expectType & ProgressEmitter>( expectType & ProgressEmitter>( cpFile('source/unicorn.png', 'destination/unicorn.png', {overwrite: false}) ); +expectType & ProgressEmitter>( + cpFile('source/unicorn.png', 'destination/unicorn.png', { + directoryMode: 0o700 + }) +); +expectError( + await cpFile('source/unicorn.png', 'destination/unicorn.png', { + directoryMode: '700' + }) +); expectType>( cpFile('source/unicorn.png', 'destination/unicorn.png').on( 'progress', @@ -29,3 +39,13 @@ expectType( overwrite: false }) ); +expectType( + cpFile.sync('source/unicorn.png', 'destination/unicorn.png', { + directoryMode: 0o700 + }) +); +expectError( + cpFile.sync('source/unicorn.png', 'destination/unicorn.png', { + directoryMode: '700' + }) +); diff --git a/readme.md b/readme.md index 0acce2a..5f380e9 100644 --- a/readme.md +++ b/readme.md @@ -59,6 +59,13 @@ Default: `true` Overwrite existing destination file. +##### directoryMode + +Type: `number`\ +Default: `0o777` + +[Permissions](https://en.wikipedia.org/wiki/File-system_permissions#Numeric_notation) for created directories. Not supported on Windows. + ### cpFile.on('progress', handler) Progress reporting. Only available when using the async method. diff --git a/test/async.js b/test/async.js index bf62b5a..8479bb2 100644 --- a/test/async.js +++ b/test/async.js @@ -80,6 +80,15 @@ test('do not overwrite when disabled', async t => { t.is(error.code, 'EEXIST', error.message); }); +test('create directories with specified mode', async t => { + const directory = t.context.destination; + const destination = `${directory}/${uuidv4()}`; + const directoryMode = 0o700; + await cpFile('license', destination, {directoryMode}); + const stat = fs.statSync(directory); + t.is(stat.mode & directoryMode, directoryMode); +}); + test('do not create `destination` on unreadable `source`', async t => { const error = await t.throwsAsync(cpFile('node_modules', t.context.destination)); t.is(error.name, 'CpFileError', error.message); diff --git a/test/sync.js b/test/sync.js index caec879..53bf589 100644 --- a/test/sync.js +++ b/test/sync.js @@ -81,6 +81,15 @@ test('do not overwrite when disabled', t => { t.is(fs.readFileSync(t.context.destination, 'utf8'), ''); }); +test('create directories with specified mode', t => { + const directory = t.context.destination; + const destination = `${directory}/${uuidv4()}`; + const directoryMode = 0o700; + cpFile.sync('license', destination, {directoryMode}); + const stat = fs.statSync(directory); + t.is(stat.mode & directoryMode, directoryMode); +}); + test('do not create `destination` on unreadable `source`', t => { t.throws( () => {