source: trip-planner-front/node_modules/tar/lib/mkdir.js

Last change on this file was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 5.2 KB
RevLine 
[6a3a178]1'use strict'
2// wrapper around mkdirp for tar's needs.
3
4// TODO: This should probably be a class, not functionally
5// passing around state in a gazillion args.
6
7const mkdirp = require('mkdirp')
8const fs = require('fs')
9const path = require('path')
10const chownr = require('chownr')
11const normPath = require('./normalize-windows-path.js')
12
13class SymlinkError extends Error {
14 constructor (symlink, path) {
15 super('Cannot extract through symbolic link')
16 this.path = path
17 this.symlink = symlink
18 }
19
20 get name () {
21 return 'SylinkError'
22 }
23}
24
25class CwdError extends Error {
26 constructor (path, code) {
27 super(code + ': Cannot cd into \'' + path + '\'')
28 this.path = path
29 this.code = code
30 }
31
32 get name () {
33 return 'CwdError'
34 }
35}
36
37const cGet = (cache, key) => cache.get(normPath(key))
38const cSet = (cache, key, val) => cache.set(normPath(key), val)
39
40const checkCwd = (dir, cb) => {
41 fs.stat(dir, (er, st) => {
42 if (er || !st.isDirectory())
43 er = new CwdError(dir, er && er.code || 'ENOTDIR')
44 cb(er)
45 })
46}
47
48module.exports = (dir, opt, cb) => {
49 dir = normPath(dir)
50
51 // if there's any overlap between mask and mode,
52 // then we'll need an explicit chmod
53 const umask = opt.umask
54 const mode = opt.mode | 0o0700
55 const needChmod = (mode & umask) !== 0
56
57 const uid = opt.uid
58 const gid = opt.gid
59 const doChown = typeof uid === 'number' &&
60 typeof gid === 'number' &&
61 (uid !== opt.processUid || gid !== opt.processGid)
62
63 const preserve = opt.preserve
64 const unlink = opt.unlink
65 const cache = opt.cache
66 const cwd = normPath(opt.cwd)
67
68 const done = (er, created) => {
69 if (er)
70 cb(er)
71 else {
72 cSet(cache, dir, true)
73 if (created && doChown)
74 chownr(created, uid, gid, er => done(er))
75 else if (needChmod)
76 fs.chmod(dir, mode, cb)
77 else
78 cb()
79 }
80 }
81
82 if (cache && cGet(cache, dir) === true)
83 return done()
84
85 if (dir === cwd)
86 return checkCwd(dir, done)
87
88 if (preserve)
89 return mkdirp(dir, {mode}).then(made => done(null, made), done)
90
91 const sub = normPath(path.relative(cwd, dir))
92 const parts = sub.split('/')
93 mkdir_(cwd, parts, mode, cache, unlink, cwd, null, done)
94}
95
96const mkdir_ = (base, parts, mode, cache, unlink, cwd, created, cb) => {
97 if (!parts.length)
98 return cb(null, created)
99 const p = parts.shift()
100 const part = normPath(path.resolve(base + '/' + p))
101 if (cGet(cache, part))
102 return mkdir_(part, parts, mode, cache, unlink, cwd, created, cb)
103 fs.mkdir(part, mode, onmkdir(part, parts, mode, cache, unlink, cwd, created, cb))
104}
105
106const onmkdir = (part, parts, mode, cache, unlink, cwd, created, cb) => er => {
107 if (er) {
108 fs.lstat(part, (statEr, st) => {
109 if (statEr) {
110 statEr.path = statEr.path && normPath(statEr.path)
111 cb(statEr)
112 } else if (st.isDirectory())
113 mkdir_(part, parts, mode, cache, unlink, cwd, created, cb)
114 else if (unlink) {
115 fs.unlink(part, er => {
116 if (er)
117 return cb(er)
118 fs.mkdir(part, mode, onmkdir(part, parts, mode, cache, unlink, cwd, created, cb))
119 })
120 } else if (st.isSymbolicLink())
121 return cb(new SymlinkError(part, part + '/' + parts.join('/')))
122 else
123 cb(er)
124 })
125 } else {
126 created = created || part
127 mkdir_(part, parts, mode, cache, unlink, cwd, created, cb)
128 }
129}
130
131const checkCwdSync = dir => {
132 let ok = false
133 let code = 'ENOTDIR'
134 try {
135 ok = fs.statSync(dir).isDirectory()
136 } catch (er) {
137 code = er.code
138 } finally {
139 if (!ok)
140 throw new CwdError(dir, code)
141 }
142}
143
144module.exports.sync = (dir, opt) => {
145 dir = normPath(dir)
146 // if there's any overlap between mask and mode,
147 // then we'll need an explicit chmod
148 const umask = opt.umask
149 const mode = opt.mode | 0o0700
150 const needChmod = (mode & umask) !== 0
151
152 const uid = opt.uid
153 const gid = opt.gid
154 const doChown = typeof uid === 'number' &&
155 typeof gid === 'number' &&
156 (uid !== opt.processUid || gid !== opt.processGid)
157
158 const preserve = opt.preserve
159 const unlink = opt.unlink
160 const cache = opt.cache
161 const cwd = normPath(opt.cwd)
162
163 const done = (created) => {
164 cSet(cache, dir, true)
165 if (created && doChown)
166 chownr.sync(created, uid, gid)
167 if (needChmod)
168 fs.chmodSync(dir, mode)
169 }
170
171 if (cache && cGet(cache, dir) === true)
172 return done()
173
174 if (dir === cwd) {
175 checkCwdSync(cwd)
176 return done()
177 }
178
179 if (preserve)
180 return done(mkdirp.sync(dir, mode))
181
182 const sub = normPath(path.relative(cwd, dir))
183 const parts = sub.split('/')
184 let created = null
185 for (let p = parts.shift(), part = cwd;
186 p && (part += '/' + p);
187 p = parts.shift()) {
188 part = normPath(path.resolve(part))
189 if (cGet(cache, part))
190 continue
191
192 try {
193 fs.mkdirSync(part, mode)
194 created = created || part
195 cSet(cache, part, true)
196 } catch (er) {
197 const st = fs.lstatSync(part)
198 if (st.isDirectory()) {
199 cSet(cache, part, true)
200 continue
201 } else if (unlink) {
202 fs.unlinkSync(part)
203 fs.mkdirSync(part, mode)
204 created = created || part
205 cSet(cache, part, true)
206 continue
207 } else if (st.isSymbolicLink())
208 return new SymlinkError(part, part + '/' + parts.join('/'))
209 }
210 }
211
212 return done(created)
213}
Note: See TracBrowser for help on using the repository browser.