cacache 16.0.7 → 16.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -0
- package/lib/content/read.js +76 -91
- package/lib/content/rm.js +9 -9
- package/lib/content/write.js +32 -32
- package/lib/entry-index.js +92 -104
- package/lib/get.js +68 -73
- package/lib/put.js +14 -21
- package/lib/util/fix-owner.js +36 -39
- package/lib/util/move-file.js +35 -48
- package/lib/util/tmp.js +5 -7
- package/lib/verify.js +156 -192
- package/package.json +3 -7
package/lib/entry-index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const util = require('util')
|
|
4
4
|
const crypto = require('crypto')
|
|
5
|
-
const fs = require('fs')
|
|
5
|
+
const fs = require('@npmcli/fs')
|
|
6
6
|
const Minipass = require('minipass')
|
|
7
7
|
const path = require('path')
|
|
8
8
|
const ssri = require('ssri')
|
|
@@ -17,11 +17,6 @@ const _rimraf = require('rimraf')
|
|
|
17
17
|
const rimraf = util.promisify(_rimraf)
|
|
18
18
|
rimraf.sync = _rimraf.sync
|
|
19
19
|
|
|
20
|
-
const appendFile = util.promisify(fs.appendFile)
|
|
21
|
-
const readFile = util.promisify(fs.readFile)
|
|
22
|
-
const readdir = util.promisify(fs.readdir)
|
|
23
|
-
const writeFile = util.promisify(fs.writeFile)
|
|
24
|
-
|
|
25
20
|
module.exports.NotFoundError = class NotFoundError extends Error {
|
|
26
21
|
constructor (cache, key) {
|
|
27
22
|
super(`No cache entry for ${key} found in ${cache}`)
|
|
@@ -85,7 +80,7 @@ async function compact (cache, key, matchFn, opts = {}) {
|
|
|
85
80
|
}
|
|
86
81
|
|
|
87
82
|
const write = async (tmp) => {
|
|
88
|
-
await writeFile(tmp.target, newIndex, { flag: 'wx' })
|
|
83
|
+
await fs.writeFile(tmp.target, newIndex, { flag: 'wx' })
|
|
89
84
|
await fixOwner.mkdirfix(cache, path.dirname(bucket))
|
|
90
85
|
// we use @npmcli/move-file directly here because we
|
|
91
86
|
// want to overwrite the existing file
|
|
@@ -118,7 +113,7 @@ async function compact (cache, key, matchFn, opts = {}) {
|
|
|
118
113
|
|
|
119
114
|
module.exports.insert = insert
|
|
120
115
|
|
|
121
|
-
function insert (cache, key, integrity, opts = {}) {
|
|
116
|
+
async function insert (cache, key, integrity, opts = {}) {
|
|
122
117
|
const { metadata, size } = opts
|
|
123
118
|
const bucket = bucketPath(cache, key)
|
|
124
119
|
const entry = {
|
|
@@ -128,36 +123,32 @@ function insert (cache, key, integrity, opts = {}) {
|
|
|
128
123
|
size,
|
|
129
124
|
metadata,
|
|
130
125
|
}
|
|
131
|
-
|
|
132
|
-
.mkdirfix(cache, path.dirname(bucket))
|
|
133
|
-
.
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
.
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
return undefined
|
|
149
|
-
}
|
|
126
|
+
try {
|
|
127
|
+
await fixOwner.mkdirfix(cache, path.dirname(bucket))
|
|
128
|
+
const stringified = JSON.stringify(entry)
|
|
129
|
+
// NOTE - Cleverness ahoy!
|
|
130
|
+
//
|
|
131
|
+
// This works because it's tremendously unlikely for an entry to corrupt
|
|
132
|
+
// another while still preserving the string length of the JSON in
|
|
133
|
+
// question. So, we just slap the length in there and verify it on read.
|
|
134
|
+
//
|
|
135
|
+
// Thanks to @isaacs for the whiteboarding session that ended up with
|
|
136
|
+
// this.
|
|
137
|
+
await fs.appendFile(bucket, `\n${hashEntry(stringified)}\t${stringified}`)
|
|
138
|
+
await fixOwner.chownr(cache, bucket)
|
|
139
|
+
} catch (err) {
|
|
140
|
+
if (err.code === 'ENOENT') {
|
|
141
|
+
return undefined
|
|
142
|
+
}
|
|
150
143
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
return formatEntry(cache, entry)
|
|
160
|
-
})
|
|
144
|
+
throw err
|
|
145
|
+
// There's a class of race conditions that happen when things get deleted
|
|
146
|
+
// during fixOwner, or between the two mkdirfix/chownr calls.
|
|
147
|
+
//
|
|
148
|
+
// It's perfectly fine to just not bother in those cases and lie
|
|
149
|
+
// that the index entry was written. Because it's a cache.
|
|
150
|
+
}
|
|
151
|
+
return formatEntry(cache, entry)
|
|
161
152
|
}
|
|
162
153
|
|
|
163
154
|
module.exports.insert.sync = insertSync
|
|
@@ -187,25 +178,24 @@ function insertSync (cache, key, integrity, opts = {}) {
|
|
|
187
178
|
|
|
188
179
|
module.exports.find = find
|
|
189
180
|
|
|
190
|
-
function find (cache, key) {
|
|
181
|
+
async function find (cache, key) {
|
|
191
182
|
const bucket = bucketPath(cache, key)
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
} else {
|
|
198
|
-
return latest
|
|
199
|
-
}
|
|
200
|
-
}, null)
|
|
201
|
-
})
|
|
202
|
-
.catch((err) => {
|
|
203
|
-
if (err.code === 'ENOENT') {
|
|
204
|
-
return null
|
|
183
|
+
try {
|
|
184
|
+
const entries = await bucketEntries(bucket)
|
|
185
|
+
return entries.reduce((latest, next) => {
|
|
186
|
+
if (next && next.key === key) {
|
|
187
|
+
return formatEntry(cache, next)
|
|
205
188
|
} else {
|
|
206
|
-
|
|
189
|
+
return latest
|
|
207
190
|
}
|
|
208
|
-
})
|
|
191
|
+
}, null)
|
|
192
|
+
} catch (err) {
|
|
193
|
+
if (err.code === 'ENOENT') {
|
|
194
|
+
return null
|
|
195
|
+
} else {
|
|
196
|
+
throw err
|
|
197
|
+
}
|
|
198
|
+
}
|
|
209
199
|
}
|
|
210
200
|
|
|
211
201
|
module.exports.find.sync = findSync
|
|
@@ -257,67 +247,65 @@ function lsStream (cache) {
|
|
|
257
247
|
const indexDir = bucketDir(cache)
|
|
258
248
|
const stream = new Minipass({ objectMode: true })
|
|
259
249
|
|
|
260
|
-
|
|
261
|
-
|
|
250
|
+
// Set all this up to run on the stream and then just return the stream
|
|
251
|
+
Promise.resolve().then(async () => {
|
|
252
|
+
const buckets = await readdirOrEmpty(indexDir)
|
|
253
|
+
await Promise.all(buckets.map(async (bucket) => {
|
|
262
254
|
const bucketPath = path.join(indexDir, bucket)
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
))
|
|
298
|
-
.then(
|
|
299
|
-
() => stream.end(),
|
|
300
|
-
err => stream.emit('error', err)
|
|
301
|
-
)
|
|
255
|
+
const subbuckets = await readdirOrEmpty(bucketPath)
|
|
256
|
+
await Promise.all(subbuckets.map(async (subbucket) => {
|
|
257
|
+
const subbucketPath = path.join(bucketPath, subbucket)
|
|
258
|
+
|
|
259
|
+
// "/cachename/<bucket 0xFF>/<bucket 0xFF>./*"
|
|
260
|
+
const subbucketEntries = await readdirOrEmpty(subbucketPath)
|
|
261
|
+
await Promise.all(subbucketEntries.map(async (entry) => {
|
|
262
|
+
const entryPath = path.join(subbucketPath, entry)
|
|
263
|
+
try {
|
|
264
|
+
const entries = await bucketEntries(entryPath)
|
|
265
|
+
// using a Map here prevents duplicate keys from showing up
|
|
266
|
+
// twice, I guess?
|
|
267
|
+
const reduced = entries.reduce((acc, entry) => {
|
|
268
|
+
acc.set(entry.key, entry)
|
|
269
|
+
return acc
|
|
270
|
+
}, new Map())
|
|
271
|
+
// reduced is a map of key => entry
|
|
272
|
+
for (const entry of reduced.values()) {
|
|
273
|
+
const formatted = formatEntry(cache, entry)
|
|
274
|
+
if (formatted) {
|
|
275
|
+
stream.write(formatted)
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
} catch (err) {
|
|
279
|
+
if (err.code === 'ENOENT') {
|
|
280
|
+
return undefined
|
|
281
|
+
}
|
|
282
|
+
throw err
|
|
283
|
+
}
|
|
284
|
+
}))
|
|
285
|
+
}))
|
|
286
|
+
}))
|
|
287
|
+
stream.end()
|
|
288
|
+
return stream
|
|
289
|
+
}).catch(err => stream.emit('error', err))
|
|
302
290
|
|
|
303
291
|
return stream
|
|
304
292
|
}
|
|
305
293
|
|
|
306
294
|
module.exports.ls = ls
|
|
307
295
|
|
|
308
|
-
function ls (cache) {
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
)
|
|
296
|
+
async function ls (cache) {
|
|
297
|
+
const entries = await lsStream(cache).collect()
|
|
298
|
+
return entries.reduce((acc, xs) => {
|
|
299
|
+
acc[xs.key] = xs
|
|
300
|
+
return acc
|
|
301
|
+
}, {})
|
|
315
302
|
}
|
|
316
303
|
|
|
317
304
|
module.exports.bucketEntries = bucketEntries
|
|
318
305
|
|
|
319
|
-
function bucketEntries (bucket, filter) {
|
|
320
|
-
|
|
306
|
+
async function bucketEntries (bucket, filter) {
|
|
307
|
+
const data = await fs.readFile(bucket, 'utf8')
|
|
308
|
+
return _bucketEntries(data, filter)
|
|
321
309
|
}
|
|
322
310
|
|
|
323
311
|
module.exports.bucketEntries.sync = bucketEntriesSync
|
|
@@ -406,7 +394,7 @@ function formatEntry (cache, entry, keepAll) {
|
|
|
406
394
|
}
|
|
407
395
|
|
|
408
396
|
function readdirOrEmpty (dir) {
|
|
409
|
-
return readdir(dir).catch((err) => {
|
|
397
|
+
return fs.readdir(dir).catch((err) => {
|
|
410
398
|
if (err.code === 'ENOENT' || err.code === 'ENOTDIR') {
|
|
411
399
|
return []
|
|
412
400
|
}
|
package/lib/get.js
CHANGED
|
@@ -8,52 +8,48 @@ const index = require('./entry-index')
|
|
|
8
8
|
const memo = require('./memoization')
|
|
9
9
|
const read = require('./content/read')
|
|
10
10
|
|
|
11
|
-
function getData (cache, key, opts = {}) {
|
|
11
|
+
async function getData (cache, key, opts = {}) {
|
|
12
12
|
const { integrity, memoize, size } = opts
|
|
13
13
|
const memoized = memo.get(cache, key, opts)
|
|
14
14
|
if (memoized && memoize !== false) {
|
|
15
|
-
return
|
|
15
|
+
return {
|
|
16
16
|
metadata: memoized.entry.metadata,
|
|
17
17
|
data: memoized.data,
|
|
18
18
|
integrity: memoized.entry.integrity,
|
|
19
19
|
size: memoized.entry.size,
|
|
20
|
-
}
|
|
20
|
+
}
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
const entry = await index.find(cache, key, opts)
|
|
24
|
+
if (!entry) {
|
|
25
|
+
throw new index.NotFoundError(cache, key)
|
|
26
|
+
}
|
|
27
|
+
const data = await read(cache, entry.integrity, { integrity, size })
|
|
28
|
+
if (memoize) {
|
|
29
|
+
memo.put(cache, entry, data, opts)
|
|
30
|
+
}
|
|
27
31
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
data,
|
|
35
|
-
metadata: entry.metadata,
|
|
36
|
-
size: entry.size,
|
|
37
|
-
integrity: entry.integrity,
|
|
38
|
-
}
|
|
39
|
-
})
|
|
40
|
-
})
|
|
32
|
+
return {
|
|
33
|
+
data,
|
|
34
|
+
metadata: entry.metadata,
|
|
35
|
+
size: entry.size,
|
|
36
|
+
integrity: entry.integrity,
|
|
37
|
+
}
|
|
41
38
|
}
|
|
42
39
|
module.exports = getData
|
|
43
40
|
|
|
44
|
-
function getDataByDigest (cache, key, opts = {}) {
|
|
41
|
+
async function getDataByDigest (cache, key, opts = {}) {
|
|
45
42
|
const { integrity, memoize, size } = opts
|
|
46
43
|
const memoized = memo.get.byDigest(cache, key, opts)
|
|
47
44
|
if (memoized && memoize !== false) {
|
|
48
|
-
return
|
|
45
|
+
return memoized
|
|
49
46
|
}
|
|
50
47
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
})
|
|
48
|
+
const res = await read(cache, key, { integrity, size })
|
|
49
|
+
if (memoize) {
|
|
50
|
+
memo.put.byDigest(cache, key, res, opts)
|
|
51
|
+
}
|
|
52
|
+
return res
|
|
57
53
|
}
|
|
58
54
|
module.exports.byDigest = getDataByDigest
|
|
59
55
|
|
|
@@ -131,36 +127,36 @@ function getStream (cache, key, opts = {}) {
|
|
|
131
127
|
}
|
|
132
128
|
|
|
133
129
|
const stream = new Pipeline()
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
.
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
})
|
|
149
|
-
|
|
150
|
-
const src = read.readStream(
|
|
151
|
-
cache,
|
|
152
|
-
entry.integrity,
|
|
153
|
-
{ ...opts, size: typeof size !== 'number' ? entry.size : size }
|
|
154
|
-
)
|
|
155
|
-
|
|
156
|
-
if (memoize) {
|
|
157
|
-
const memoStream = new Collect.PassThrough()
|
|
158
|
-
memoStream.on('collect', data => memo.put(cache, entry, data, opts))
|
|
159
|
-
stream.unshift(memoStream)
|
|
160
|
-
}
|
|
161
|
-
stream.unshift(src)
|
|
130
|
+
// Set all this up to run on the stream and then just return the stream
|
|
131
|
+
Promise.resolve().then(async () => {
|
|
132
|
+
const entry = await index.find(cache, key)
|
|
133
|
+
if (!entry) {
|
|
134
|
+
throw new index.NotFoundError(cache, key)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
stream.emit('metadata', entry.metadata)
|
|
138
|
+
stream.emit('integrity', entry.integrity)
|
|
139
|
+
stream.emit('size', entry.size)
|
|
140
|
+
stream.on('newListener', function (ev, cb) {
|
|
141
|
+
ev === 'metadata' && cb(entry.metadata)
|
|
142
|
+
ev === 'integrity' && cb(entry.integrity)
|
|
143
|
+
ev === 'size' && cb(entry.size)
|
|
162
144
|
})
|
|
163
|
-
|
|
145
|
+
|
|
146
|
+
const src = read.readStream(
|
|
147
|
+
cache,
|
|
148
|
+
entry.integrity,
|
|
149
|
+
{ ...opts, size: typeof size !== 'number' ? entry.size : size }
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
if (memoize) {
|
|
153
|
+
const memoStream = new Collect.PassThrough()
|
|
154
|
+
memoStream.on('collect', data => memo.put(cache, entry, data, opts))
|
|
155
|
+
stream.unshift(memoStream)
|
|
156
|
+
}
|
|
157
|
+
stream.unshift(src)
|
|
158
|
+
return stream
|
|
159
|
+
}).catch((err) => stream.emit('error', err))
|
|
164
160
|
|
|
165
161
|
return stream
|
|
166
162
|
}
|
|
@@ -204,27 +200,26 @@ function info (cache, key, opts = {}) {
|
|
|
204
200
|
}
|
|
205
201
|
module.exports.info = info
|
|
206
202
|
|
|
207
|
-
function copy (cache, key, dest, opts = {}) {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
}
|
|
219
|
-
})
|
|
220
|
-
})
|
|
203
|
+
async function copy (cache, key, dest, opts = {}) {
|
|
204
|
+
const entry = await index.find(cache, key, opts)
|
|
205
|
+
if (!entry) {
|
|
206
|
+
throw new index.NotFoundError(cache, key)
|
|
207
|
+
}
|
|
208
|
+
await read.copy(cache, entry.integrity, dest, opts)
|
|
209
|
+
return {
|
|
210
|
+
metadata: entry.metadata,
|
|
211
|
+
size: entry.size,
|
|
212
|
+
integrity: entry.integrity,
|
|
213
|
+
}
|
|
221
214
|
}
|
|
222
215
|
|
|
223
216
|
module.exports.copy = copy
|
|
224
217
|
|
|
225
|
-
function copyByDigest (cache, key, dest, opts = {}) {
|
|
226
|
-
|
|
218
|
+
async function copyByDigest (cache, key, dest, opts = {}) {
|
|
219
|
+
await read.copy(cache, key, dest, opts)
|
|
220
|
+
return key
|
|
227
221
|
}
|
|
222
|
+
|
|
228
223
|
module.exports.copy.byDigest = copyByDigest
|
|
229
224
|
|
|
230
225
|
module.exports.hasContent = read.hasContent
|
package/lib/put.js
CHANGED
|
@@ -14,20 +14,16 @@ const putOpts = (opts) => ({
|
|
|
14
14
|
|
|
15
15
|
module.exports = putData
|
|
16
16
|
|
|
17
|
-
function putData (cache, key, data, opts = {}) {
|
|
17
|
+
async function putData (cache, key, data, opts = {}) {
|
|
18
18
|
const { memoize } = opts
|
|
19
19
|
opts = putOpts(opts)
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
memo.put(cache, entry, data, opts)
|
|
26
|
-
}
|
|
20
|
+
const res = await write(cache, data, opts)
|
|
21
|
+
const entry = await index.insert(cache, key, res.integrity, { ...opts, size: res.size })
|
|
22
|
+
if (memoize) {
|
|
23
|
+
memo.put(cache, entry, data, opts)
|
|
24
|
+
}
|
|
27
25
|
|
|
28
|
-
|
|
29
|
-
})
|
|
30
|
-
})
|
|
26
|
+
return res.integrity
|
|
31
27
|
}
|
|
32
28
|
|
|
33
29
|
module.exports.stream = putStream
|
|
@@ -68,17 +64,14 @@ function putStream (cache, key, opts = {}) {
|
|
|
68
64
|
// last but not least, we write the index and emit hash and size,
|
|
69
65
|
// and memoize if we're doing that
|
|
70
66
|
pipeline.push(new Flush({
|
|
71
|
-
flush () {
|
|
67
|
+
async flush () {
|
|
72
68
|
if (!error) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
.
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
pipeline.emit('integrity', integrity)
|
|
80
|
-
pipeline.emit('size', size)
|
|
81
|
-
})
|
|
69
|
+
const entry = await index.insert(cache, key, integrity, { ...opts, size })
|
|
70
|
+
if (memoize && memoData) {
|
|
71
|
+
memo.put(cache, entry, memoData, opts)
|
|
72
|
+
}
|
|
73
|
+
pipeline.emit('integrity', integrity)
|
|
74
|
+
pipeline.emit('size', size)
|
|
82
75
|
}
|
|
83
76
|
},
|
|
84
77
|
}))
|
package/lib/util/fix-owner.js
CHANGED
|
@@ -33,40 +33,38 @@ const getSelf = () => {
|
|
|
33
33
|
|
|
34
34
|
module.exports.chownr = fixOwner
|
|
35
35
|
|
|
36
|
-
function fixOwner (cache, filepath) {
|
|
36
|
+
async function fixOwner (cache, filepath) {
|
|
37
37
|
if (!process.getuid) {
|
|
38
38
|
// This platform doesn't need ownership fixing
|
|
39
|
-
return
|
|
39
|
+
return
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
getSelf()
|
|
43
43
|
if (self.uid !== 0) {
|
|
44
44
|
// almost certainly can't chown anyway
|
|
45
|
-
return
|
|
45
|
+
return
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
const { uid, gid } = owner
|
|
48
|
+
const { uid, gid } = await inferOwner(cache)
|
|
50
49
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
50
|
+
// No need to override if it's already what we used.
|
|
51
|
+
if (self.uid === uid && self.gid === gid) {
|
|
52
|
+
return
|
|
53
|
+
}
|
|
55
54
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
})
|
|
55
|
+
return inflight('fixOwner: fixing ownership on ' + filepath, () =>
|
|
56
|
+
chownr(
|
|
57
|
+
filepath,
|
|
58
|
+
typeof uid === 'number' ? uid : self.uid,
|
|
59
|
+
typeof gid === 'number' ? gid : self.gid
|
|
60
|
+
).catch((err) => {
|
|
61
|
+
if (err.code === 'ENOENT') {
|
|
62
|
+
return null
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
throw err
|
|
66
|
+
})
|
|
67
|
+
)
|
|
70
68
|
}
|
|
71
69
|
|
|
72
70
|
module.exports.chownr.sync = fixOwnerSync
|
|
@@ -105,26 +103,25 @@ function fixOwnerSync (cache, filepath) {
|
|
|
105
103
|
|
|
106
104
|
module.exports.mkdirfix = mkdirfix
|
|
107
105
|
|
|
108
|
-
function mkdirfix (cache, p, cb) {
|
|
106
|
+
async function mkdirfix (cache, p, cb) {
|
|
109
107
|
// we have to infer the owner _before_ making the directory, even though
|
|
110
108
|
// we aren't going to use the results, since the cache itself might not
|
|
111
109
|
// exist yet. If we mkdirp it, then our current uid/gid will be assumed
|
|
112
110
|
// to be correct if it creates the cache folder in the process.
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
})
|
|
111
|
+
await inferOwner(cache)
|
|
112
|
+
try {
|
|
113
|
+
const made = await mkdirp(p)
|
|
114
|
+
if (made) {
|
|
115
|
+
await fixOwner(cache, made)
|
|
116
|
+
return made
|
|
117
|
+
}
|
|
118
|
+
} catch (err) {
|
|
119
|
+
if (err.code === 'EEXIST') {
|
|
120
|
+
await fixOwner(cache, p)
|
|
121
|
+
return null
|
|
122
|
+
}
|
|
123
|
+
throw err
|
|
124
|
+
}
|
|
128
125
|
}
|
|
129
126
|
|
|
130
127
|
module.exports.mkdirfix.sync = mkdirfixSync
|