source: node_modules/tar/lib/mkdir.js@ 62b2964

finki-main main
Last change on this file since 62b2964 was 81bc7da, checked in by Klimentina Efremova <klimentina08642@…>, 3 months ago

Initial commit

  • Property mode set to 100644
File size: 5.4 KB
Line 
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 }
45 cb(er)
46 })
47}
48
49module.exports = (dir, opt, cb) => {
50 dir = normPath(dir)
51
52 // if there's any overlap between mask and mode,
53 // then we'll need an explicit chmod
54 const umask = opt.umask
55 const mode = opt.mode | 0o0700
56 const needChmod = (mode & umask) !== 0
57
58 const uid = opt.uid
59 const gid = opt.gid
60 const doChown = typeof uid === 'number' &&
61 typeof gid === 'number' &&
62 (uid !== opt.processUid || gid !== opt.processGid)
63
64 const preserve = opt.preserve
65 const unlink = opt.unlink
66 const cache = opt.cache
67 const cwd = normPath(opt.cwd)
68
69 const done = (er, created) => {
70 if (er) {
71 cb(er)
72 } else {
73 cSet(cache, dir, true)
74 if (created && doChown) {
75 chownr(created, uid, gid, er => done(er))
76 } else if (needChmod) {
77 fs.chmod(dir, mode, cb)
78 } else {
79 cb()
80 }
81 }
82 }
83
84 if (cache && cGet(cache, dir) === true) {
85 return done()
86 }
87
88 if (dir === cwd) {
89 return checkCwd(dir, done)
90 }
91
92 if (preserve) {
93 return mkdirp(dir, { mode }).then(made => done(null, made), done)
94 }
95
96 const sub = normPath(path.relative(cwd, dir))
97 const parts = sub.split('/')
98 mkdir_(cwd, parts, mode, cache, unlink, cwd, null, done)
99}
100
101const mkdir_ = (base, parts, mode, cache, unlink, cwd, created, cb) => {
102 if (!parts.length) {
103 return cb(null, created)
104 }
105 const p = parts.shift()
106 const part = normPath(path.resolve(base + '/' + p))
107 if (cGet(cache, part)) {
108 return mkdir_(part, parts, mode, cache, unlink, cwd, created, cb)
109 }
110 fs.mkdir(part, mode, onmkdir(part, parts, mode, cache, unlink, cwd, created, cb))
111}
112
113const onmkdir = (part, parts, mode, cache, unlink, cwd, created, cb) => er => {
114 if (er) {
115 fs.lstat(part, (statEr, st) => {
116 if (statEr) {
117 statEr.path = statEr.path && normPath(statEr.path)
118 cb(statEr)
119 } else if (st.isDirectory()) {
120 mkdir_(part, parts, mode, cache, unlink, cwd, created, cb)
121 } else if (unlink) {
122 fs.unlink(part, er => {
123 if (er) {
124 return cb(er)
125 }
126 fs.mkdir(part, mode, onmkdir(part, parts, mode, cache, unlink, cwd, created, cb))
127 })
128 } else if (st.isSymbolicLink()) {
129 return cb(new SymlinkError(part, part + '/' + parts.join('/')))
130 } else {
131 cb(er)
132 }
133 })
134 } else {
135 created = created || part
136 mkdir_(part, parts, mode, cache, unlink, cwd, created, cb)
137 }
138}
139
140const checkCwdSync = dir => {
141 let ok = false
142 let code = 'ENOTDIR'
143 try {
144 ok = fs.statSync(dir).isDirectory()
145 } catch (er) {
146 code = er.code
147 } finally {
148 if (!ok) {
149 throw new CwdError(dir, code)
150 }
151 }
152}
153
154module.exports.sync = (dir, opt) => {
155 dir = normPath(dir)
156 // if there's any overlap between mask and mode,
157 // then we'll need an explicit chmod
158 const umask = opt.umask
159 const mode = opt.mode | 0o0700
160 const needChmod = (mode & umask) !== 0
161
162 const uid = opt.uid
163 const gid = opt.gid
164 const doChown = typeof uid === 'number' &&
165 typeof gid === 'number' &&
166 (uid !== opt.processUid || gid !== opt.processGid)
167
168 const preserve = opt.preserve
169 const unlink = opt.unlink
170 const cache = opt.cache
171 const cwd = normPath(opt.cwd)
172
173 const done = (created) => {
174 cSet(cache, dir, true)
175 if (created && doChown) {
176 chownr.sync(created, uid, gid)
177 }
178 if (needChmod) {
179 fs.chmodSync(dir, mode)
180 }
181 }
182
183 if (cache && cGet(cache, dir) === true) {
184 return done()
185 }
186
187 if (dir === cwd) {
188 checkCwdSync(cwd)
189 return done()
190 }
191
192 if (preserve) {
193 return done(mkdirp.sync(dir, mode))
194 }
195
196 const sub = normPath(path.relative(cwd, dir))
197 const parts = sub.split('/')
198 let created = null
199 for (let p = parts.shift(), part = cwd;
200 p && (part += '/' + p);
201 p = parts.shift()) {
202 part = normPath(path.resolve(part))
203 if (cGet(cache, part)) {
204 continue
205 }
206
207 try {
208 fs.mkdirSync(part, mode)
209 created = created || part
210 cSet(cache, part, true)
211 } catch (er) {
212 const st = fs.lstatSync(part)
213 if (st.isDirectory()) {
214 cSet(cache, part, true)
215 continue
216 } else if (unlink) {
217 fs.unlinkSync(part)
218 fs.mkdirSync(part, mode)
219 created = created || part
220 cSet(cache, part, true)
221 continue
222 } else if (st.isSymbolicLink()) {
223 return new SymlinkError(part, part + '/' + parts.join('/'))
224 }
225 }
226 }
227
228 return done(created)
229}
Note: See TracBrowser for help on using the repository browser.