blob: 18439555f8ee252eaa6917c0db2836a39dba2c06 [file] [log] [blame]
Leo Repp58b9f112021-11-22 11:57:47 +01001'use strict';
2const fs = require('fs');
3const path = require('path');
4const pify = require('pify');
5
6const defaults = {
7 mode: 0o777 & (~process.umask()),
8 fs
9};
10
11// https://github.com/nodejs/node/issues/8987
12// https://github.com/libuv/libuv/pull/1088
13const checkPath = pth => {
14 if (process.platform === 'win32') {
15 const pathHasInvalidWinCharacters = /[<>:"|?*]/.test(pth.replace(path.parse(pth).root, ''));
16
17 if (pathHasInvalidWinCharacters) {
18 const err = new Error(`Path contains invalid characters: ${pth}`);
19 err.code = 'EINVAL';
20 throw err;
21 }
22 }
23};
24
25module.exports = (input, opts) => Promise.resolve().then(() => {
26 checkPath(input);
27 opts = Object.assign({}, defaults, opts);
28
29 const mkdir = pify(opts.fs.mkdir);
30 const stat = pify(opts.fs.stat);
31
32 const make = pth => {
33 return mkdir(pth, opts.mode)
34 .then(() => pth)
35 .catch(err => {
36 if (err.code === 'ENOENT') {
37 if (err.message.includes('null bytes') || path.dirname(pth) === pth) {
38 throw err;
39 }
40
41 return make(path.dirname(pth)).then(() => make(pth));
42 }
43
44 return stat(pth)
45 .then(stats => stats.isDirectory() ? pth : Promise.reject())
46 .catch(() => {
47 throw err;
48 });
49 });
50 };
51
52 return make(path.resolve(input));
53});
54
55module.exports.sync = (input, opts) => {
56 checkPath(input);
57 opts = Object.assign({}, defaults, opts);
58
59 const make = pth => {
60 try {
61 opts.fs.mkdirSync(pth, opts.mode);
62 } catch (err) {
63 if (err.code === 'ENOENT') {
64 if (err.message.includes('null bytes') || path.dirname(pth) === pth) {
65 throw err;
66 }
67
68 make(path.dirname(pth));
69 return make(pth);
70 }
71
72 try {
73 if (!opts.fs.statSync(pth).isDirectory()) {
74 throw new Error('The path is not a directory');
75 }
76 } catch (_) {
77 throw err;
78 }
79 }
80
81 return pth;
82 };
83
84 return make(path.resolve(input));
85};