cacache 12.0.4 → 15.0.0
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/CHANGELOG.md +108 -2
- package/README.md +66 -38
- package/get.js +173 -165
- package/index.js +39 -1
- package/lib/content/.write.js.swp +0 -0
- package/lib/content/path.js +7 -4
- package/lib/content/read.js +128 -73
- package/lib/content/rm.js +8 -9
- package/lib/content/write.js +126 -106
- package/lib/entry-index.js +144 -127
- package/lib/memoization.js +15 -10
- package/lib/util/disposer.js +30 -0
- package/lib/util/fix-owner.js +36 -19
- package/lib/util/hash-to-segments.js +1 -5
- package/lib/util/move-file.js +45 -28
- package/lib/util/tmp.js +11 -13
- package/lib/verify.js +168 -108
- package/ls.js +1 -1
- package/package.json +30 -31
- package/put.js +65 -67
- package/rm.js +5 -2
- package/README.es.md +0 -628
- package/en.js +0 -3
- package/es.js +0 -3
- package/lib/util/y.js +0 -25
- package/locales/en.js +0 -47
- package/locales/en.json +0 -7
- package/locales/es.js +0 -49
- package/locales/es.json +0 -6
package/lib/entry-index.js
CHANGED
|
@@ -1,94 +1,87 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const util = require('util')
|
|
4
4
|
|
|
5
|
-
const contentPath = require('./content/path')
|
|
6
5
|
const crypto = require('crypto')
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const fs = require('graceful-fs')
|
|
10
|
-
const hashToSegments = require('./util/hash-to-segments')
|
|
11
|
-
const ms = require('mississippi')
|
|
6
|
+
const fs = require('fs')
|
|
7
|
+
const Minipass = require('minipass')
|
|
12
8
|
const path = require('path')
|
|
13
9
|
const ssri = require('ssri')
|
|
14
|
-
const
|
|
15
|
-
|
|
10
|
+
const contentPath = require('./content/path')
|
|
11
|
+
const fixOwner = require('./util/fix-owner')
|
|
12
|
+
const hashToSegments = require('./util/hash-to-segments')
|
|
16
13
|
const indexV = require('../package.json')['cache-version'].index
|
|
17
14
|
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
const concat = ms.concat
|
|
22
|
-
const from = ms.from
|
|
15
|
+
const appendFile = util.promisify(fs.appendFile)
|
|
16
|
+
const readFile = util.promisify(fs.readFile)
|
|
17
|
+
const readdir = util.promisify(fs.readdir)
|
|
23
18
|
|
|
24
19
|
module.exports.NotFoundError = class NotFoundError extends Error {
|
|
25
20
|
constructor (cache, key) {
|
|
26
|
-
super(
|
|
21
|
+
super(`No cache entry for ${key} found in ${cache}`)
|
|
27
22
|
this.code = 'ENOENT'
|
|
28
23
|
this.cache = cache
|
|
29
24
|
this.key = key
|
|
30
25
|
}
|
|
31
26
|
}
|
|
32
27
|
|
|
33
|
-
const IndexOpts = figgyPudding({
|
|
34
|
-
metadata: {},
|
|
35
|
-
size: {}
|
|
36
|
-
})
|
|
37
|
-
|
|
38
28
|
module.exports.insert = insert
|
|
39
|
-
|
|
40
|
-
|
|
29
|
+
|
|
30
|
+
function insert (cache, key, integrity, opts = {}) {
|
|
31
|
+
const { metadata, size } = opts
|
|
41
32
|
const bucket = bucketPath(cache, key)
|
|
42
33
|
const entry = {
|
|
43
34
|
key,
|
|
44
35
|
integrity: integrity && ssri.stringify(integrity),
|
|
45
36
|
time: Date.now(),
|
|
46
|
-
size
|
|
47
|
-
metadata
|
|
37
|
+
size,
|
|
38
|
+
metadata
|
|
48
39
|
}
|
|
49
|
-
return fixOwner
|
|
50
|
-
cache, path.dirname(bucket)
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
)
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
40
|
+
return fixOwner
|
|
41
|
+
.mkdirfix(cache, path.dirname(bucket))
|
|
42
|
+
.then(() => {
|
|
43
|
+
const stringified = JSON.stringify(entry)
|
|
44
|
+
// NOTE - Cleverness ahoy!
|
|
45
|
+
//
|
|
46
|
+
// This works because it's tremendously unlikely for an entry to corrupt
|
|
47
|
+
// another while still preserving the string length of the JSON in
|
|
48
|
+
// question. So, we just slap the length in there and verify it on read.
|
|
49
|
+
//
|
|
50
|
+
// Thanks to @isaacs for the whiteboarding session that ended up with this.
|
|
51
|
+
return appendFile(bucket, `\n${hashEntry(stringified)}\t${stringified}`)
|
|
52
|
+
})
|
|
53
|
+
.then(() => fixOwner.chownr(cache, bucket))
|
|
54
|
+
.catch((err) => {
|
|
55
|
+
if (err.code === 'ENOENT') {
|
|
56
|
+
return undefined
|
|
57
|
+
}
|
|
58
|
+
throw err
|
|
59
|
+
// There's a class of race conditions that happen when things get deleted
|
|
60
|
+
// during fixOwner, or between the two mkdirfix/chownr calls.
|
|
61
|
+
//
|
|
62
|
+
// It's perfectly fine to just not bother in those cases and lie
|
|
63
|
+
// that the index entry was written. Because it's a cache.
|
|
64
|
+
})
|
|
65
|
+
.then(() => {
|
|
66
|
+
return formatEntry(cache, entry)
|
|
67
|
+
})
|
|
74
68
|
}
|
|
75
69
|
|
|
76
70
|
module.exports.insert.sync = insertSync
|
|
77
|
-
|
|
78
|
-
|
|
71
|
+
|
|
72
|
+
function insertSync (cache, key, integrity, opts = {}) {
|
|
73
|
+
const { metadata, size } = opts
|
|
79
74
|
const bucket = bucketPath(cache, key)
|
|
80
75
|
const entry = {
|
|
81
76
|
key,
|
|
82
77
|
integrity: integrity && ssri.stringify(integrity),
|
|
83
78
|
time: Date.now(),
|
|
84
|
-
size
|
|
85
|
-
metadata
|
|
79
|
+
size,
|
|
80
|
+
metadata
|
|
86
81
|
}
|
|
87
82
|
fixOwner.mkdirfix.sync(cache, path.dirname(bucket))
|
|
88
83
|
const stringified = JSON.stringify(entry)
|
|
89
|
-
fs.appendFileSync(
|
|
90
|
-
bucket, `\n${hashEntry(stringified)}\t${stringified}`
|
|
91
|
-
)
|
|
84
|
+
fs.appendFileSync(bucket, `\n${hashEntry(stringified)}\t${stringified}`)
|
|
92
85
|
try {
|
|
93
86
|
fixOwner.chownr.sync(cache, bucket)
|
|
94
87
|
} catch (err) {
|
|
@@ -100,26 +93,30 @@ function insertSync (cache, key, integrity, opts) {
|
|
|
100
93
|
}
|
|
101
94
|
|
|
102
95
|
module.exports.find = find
|
|
96
|
+
|
|
103
97
|
function find (cache, key) {
|
|
104
98
|
const bucket = bucketPath(cache, key)
|
|
105
|
-
return bucketEntries(bucket)
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
99
|
+
return bucketEntries(bucket)
|
|
100
|
+
.then((entries) => {
|
|
101
|
+
return entries.reduce((latest, next) => {
|
|
102
|
+
if (next && next.key === key) {
|
|
103
|
+
return formatEntry(cache, next)
|
|
104
|
+
} else {
|
|
105
|
+
return latest
|
|
106
|
+
}
|
|
107
|
+
}, null)
|
|
108
|
+
})
|
|
109
|
+
.catch((err) => {
|
|
110
|
+
if (err.code === 'ENOENT') {
|
|
111
|
+
return null
|
|
109
112
|
} else {
|
|
110
|
-
|
|
113
|
+
throw err
|
|
111
114
|
}
|
|
112
|
-
}
|
|
113
|
-
}).catch(err => {
|
|
114
|
-
if (err.code === 'ENOENT') {
|
|
115
|
-
return null
|
|
116
|
-
} else {
|
|
117
|
-
throw err
|
|
118
|
-
}
|
|
119
|
-
})
|
|
115
|
+
})
|
|
120
116
|
}
|
|
121
117
|
|
|
122
118
|
module.exports.find.sync = findSync
|
|
119
|
+
|
|
123
120
|
function findSync (cache, key) {
|
|
124
121
|
const bucket = bucketPath(cache, key)
|
|
125
122
|
try {
|
|
@@ -140,70 +137,80 @@ function findSync (cache, key) {
|
|
|
140
137
|
}
|
|
141
138
|
|
|
142
139
|
module.exports.delete = del
|
|
140
|
+
|
|
143
141
|
function del (cache, key, opts) {
|
|
144
142
|
return insert(cache, key, null, opts)
|
|
145
143
|
}
|
|
146
144
|
|
|
147
145
|
module.exports.delete.sync = delSync
|
|
146
|
+
|
|
148
147
|
function delSync (cache, key, opts) {
|
|
149
148
|
return insertSync(cache, key, null, opts)
|
|
150
149
|
}
|
|
151
150
|
|
|
152
151
|
module.exports.lsStream = lsStream
|
|
152
|
+
|
|
153
153
|
function lsStream (cache) {
|
|
154
154
|
const indexDir = bucketDir(cache)
|
|
155
|
-
const stream =
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
155
|
+
const stream = new Minipass({ objectMode: true })
|
|
156
|
+
|
|
157
|
+
readdirOrEmpty(indexDir).then(buckets => Promise.all(
|
|
158
|
+
buckets.map(bucket => {
|
|
159
|
+
const bucketPath = path.join(indexDir, bucket)
|
|
160
|
+
return readdirOrEmpty(bucketPath).then(subbuckets => Promise.all(
|
|
161
|
+
subbuckets.map(subbucket => {
|
|
162
|
+
const subbucketPath = path.join(bucketPath, subbucket)
|
|
163
|
+
|
|
164
|
+
// "/cachename/<bucket 0xFF>/<bucket 0xFF>./*"
|
|
165
|
+
return readdirOrEmpty(subbucketPath).then(entries => Promise.all(
|
|
166
|
+
entries.map(entry => {
|
|
167
|
+
const entryPath = path.join(subbucketPath, entry)
|
|
168
|
+
return bucketEntries(entryPath).then(entries =>
|
|
169
|
+
// using a Map here prevents duplicate keys from
|
|
170
|
+
// showing up twice, I guess?
|
|
171
|
+
entries.reduce((acc, entry) => {
|
|
172
|
+
acc.set(entry.key, entry)
|
|
173
|
+
return acc
|
|
174
|
+
}, new Map())
|
|
175
|
+
).then(reduced => {
|
|
176
|
+
// reduced is a map of key => entry
|
|
177
|
+
for (const entry of reduced.values()) {
|
|
178
|
+
const formatted = formatEntry(cache, entry)
|
|
179
|
+
if (formatted) {
|
|
180
|
+
stream.write(formatted)
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}).catch(err => {
|
|
184
|
+
if (err.code === 'ENOENT') { return undefined }
|
|
185
|
+
throw err
|
|
186
|
+
})
|
|
187
|
+
})
|
|
188
|
+
))
|
|
189
|
+
})
|
|
190
|
+
))
|
|
181
191
|
})
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
192
|
+
))
|
|
193
|
+
.then(
|
|
194
|
+
() => stream.end(),
|
|
195
|
+
err => stream.emit('error', err)
|
|
196
|
+
)
|
|
187
197
|
|
|
188
198
|
return stream
|
|
189
199
|
}
|
|
190
200
|
|
|
191
201
|
module.exports.ls = ls
|
|
202
|
+
|
|
192
203
|
function ls (cache) {
|
|
193
|
-
return
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
}))
|
|
200
|
-
})
|
|
204
|
+
return lsStream(cache).collect().then(entries =>
|
|
205
|
+
entries.reduce((acc, xs) => {
|
|
206
|
+
acc[xs.key] = xs
|
|
207
|
+
return acc
|
|
208
|
+
}, {})
|
|
209
|
+
)
|
|
201
210
|
}
|
|
202
211
|
|
|
203
212
|
function bucketEntries (bucket, filter) {
|
|
204
|
-
return
|
|
205
|
-
bucket, 'utf8'
|
|
206
|
-
).then(data => _bucketEntries(data, filter))
|
|
213
|
+
return readFile(bucket, 'utf8').then((data) => _bucketEntries(data, filter))
|
|
207
214
|
}
|
|
208
215
|
|
|
209
216
|
function bucketEntriesSync (bucket, filter) {
|
|
@@ -212,9 +219,11 @@ function bucketEntriesSync (bucket, filter) {
|
|
|
212
219
|
}
|
|
213
220
|
|
|
214
221
|
function _bucketEntries (data, filter) {
|
|
215
|
-
|
|
216
|
-
data.split('\n').forEach(entry => {
|
|
217
|
-
if (!entry) {
|
|
222
|
+
const entries = []
|
|
223
|
+
data.split('\n').forEach((entry) => {
|
|
224
|
+
if (!entry) {
|
|
225
|
+
return
|
|
226
|
+
}
|
|
218
227
|
const pieces = entry.split('\t')
|
|
219
228
|
if (!pieces[1] || hashEntry(pieces[1]) !== pieces[0]) {
|
|
220
229
|
// Hash is no good! Corruption or malice? Doesn't matter!
|
|
@@ -235,25 +244,30 @@ function _bucketEntries (data, filter) {
|
|
|
235
244
|
return entries
|
|
236
245
|
}
|
|
237
246
|
|
|
238
|
-
module.exports.
|
|
247
|
+
module.exports.bucketDir = bucketDir
|
|
248
|
+
|
|
239
249
|
function bucketDir (cache) {
|
|
240
250
|
return path.join(cache, `index-v${indexV}`)
|
|
241
251
|
}
|
|
242
252
|
|
|
243
|
-
module.exports.
|
|
253
|
+
module.exports.bucketPath = bucketPath
|
|
254
|
+
|
|
244
255
|
function bucketPath (cache, key) {
|
|
245
256
|
const hashed = hashKey(key)
|
|
246
|
-
return path.join.apply(
|
|
247
|
-
|
|
248
|
-
|
|
257
|
+
return path.join.apply(
|
|
258
|
+
path,
|
|
259
|
+
[bucketDir(cache)].concat(hashToSegments(hashed))
|
|
260
|
+
)
|
|
249
261
|
}
|
|
250
262
|
|
|
251
|
-
module.exports.
|
|
263
|
+
module.exports.hashKey = hashKey
|
|
264
|
+
|
|
252
265
|
function hashKey (key) {
|
|
253
266
|
return hash(key, 'sha256')
|
|
254
267
|
}
|
|
255
268
|
|
|
256
|
-
module.exports.
|
|
269
|
+
module.exports.hashEntry = hashEntry
|
|
270
|
+
|
|
257
271
|
function hashEntry (str) {
|
|
258
272
|
return hash(str, 'sha1')
|
|
259
273
|
}
|
|
@@ -267,7 +281,9 @@ function hash (str, digest) {
|
|
|
267
281
|
|
|
268
282
|
function formatEntry (cache, entry) {
|
|
269
283
|
// Treat null digests as deletions. They'll shadow any previous entries.
|
|
270
|
-
if (!entry.integrity) {
|
|
284
|
+
if (!entry.integrity) {
|
|
285
|
+
return null
|
|
286
|
+
}
|
|
271
287
|
return {
|
|
272
288
|
key: entry.key,
|
|
273
289
|
integrity: entry.integrity,
|
|
@@ -279,10 +295,11 @@ function formatEntry (cache, entry) {
|
|
|
279
295
|
}
|
|
280
296
|
|
|
281
297
|
function readdirOrEmpty (dir) {
|
|
282
|
-
return
|
|
283
|
-
.
|
|
284
|
-
|
|
285
|
-
}
|
|
298
|
+
return readdir(dir).catch((err) => {
|
|
299
|
+
if (err.code === 'ENOENT' || err.code === 'ENOTDIR') {
|
|
300
|
+
return []
|
|
301
|
+
}
|
|
286
302
|
|
|
287
|
-
|
|
303
|
+
throw err
|
|
304
|
+
})
|
|
288
305
|
}
|
package/lib/memoization.js
CHANGED
|
@@ -5,19 +5,14 @@ const LRU = require('lru-cache')
|
|
|
5
5
|
const MAX_SIZE = 50 * 1024 * 1024 // 50MB
|
|
6
6
|
const MAX_AGE = 3 * 60 * 1000
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
const MEMOIZED = new LRU({
|
|
9
9
|
max: MAX_SIZE,
|
|
10
10
|
maxAge: MAX_AGE,
|
|
11
|
-
length: (entry, key) =>
|
|
12
|
-
if (key.startsWith('key:')) {
|
|
13
|
-
return entry.data.length
|
|
14
|
-
} else if (key.startsWith('digest:')) {
|
|
15
|
-
return entry.length
|
|
16
|
-
}
|
|
17
|
-
}
|
|
11
|
+
length: (entry, key) => key.startsWith('key:') ? entry.data.length : entry.length
|
|
18
12
|
})
|
|
19
13
|
|
|
20
14
|
module.exports.clearMemoized = clearMemoized
|
|
15
|
+
|
|
21
16
|
function clearMemoized () {
|
|
22
17
|
const old = {}
|
|
23
18
|
MEMOIZED.forEach((v, k) => {
|
|
@@ -28,22 +23,26 @@ function clearMemoized () {
|
|
|
28
23
|
}
|
|
29
24
|
|
|
30
25
|
module.exports.put = put
|
|
26
|
+
|
|
31
27
|
function put (cache, entry, data, opts) {
|
|
32
28
|
pickMem(opts).set(`key:${cache}:${entry.key}`, { entry, data })
|
|
33
29
|
putDigest(cache, entry.integrity, data, opts)
|
|
34
30
|
}
|
|
35
31
|
|
|
36
32
|
module.exports.put.byDigest = putDigest
|
|
33
|
+
|
|
37
34
|
function putDigest (cache, integrity, data, opts) {
|
|
38
35
|
pickMem(opts).set(`digest:${cache}:${integrity}`, data)
|
|
39
36
|
}
|
|
40
37
|
|
|
41
38
|
module.exports.get = get
|
|
39
|
+
|
|
42
40
|
function get (cache, key, opts) {
|
|
43
41
|
return pickMem(opts).get(`key:${cache}:${key}`)
|
|
44
42
|
}
|
|
45
43
|
|
|
46
44
|
module.exports.get.byDigest = getDigest
|
|
45
|
+
|
|
47
46
|
function getDigest (cache, integrity, opts) {
|
|
48
47
|
return pickMem(opts).get(`digest:${cache}:${integrity}`)
|
|
49
48
|
}
|
|
@@ -52,8 +51,14 @@ class ObjProxy {
|
|
|
52
51
|
constructor (obj) {
|
|
53
52
|
this.obj = obj
|
|
54
53
|
}
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
|
|
55
|
+
get (key) {
|
|
56
|
+
return this.obj[key]
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
set (key, val) {
|
|
60
|
+
this.obj[key] = val
|
|
61
|
+
}
|
|
57
62
|
}
|
|
58
63
|
|
|
59
64
|
function pickMem (opts) {
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
module.exports.disposer = disposer
|
|
4
|
+
|
|
5
|
+
function disposer (creatorFn, disposerFn, fn) {
|
|
6
|
+
const runDisposer = (resource, result, shouldThrow = false) => {
|
|
7
|
+
return disposerFn(resource)
|
|
8
|
+
.then(
|
|
9
|
+
// disposer resolved, do something with original fn's promise
|
|
10
|
+
() => {
|
|
11
|
+
if (shouldThrow) {
|
|
12
|
+
throw result
|
|
13
|
+
}
|
|
14
|
+
return result
|
|
15
|
+
},
|
|
16
|
+
// Disposer fn failed, crash process
|
|
17
|
+
(err) => {
|
|
18
|
+
throw err
|
|
19
|
+
// Or process.exit?
|
|
20
|
+
})
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return creatorFn
|
|
24
|
+
.then((resource) => {
|
|
25
|
+
// fn(resource) can throw, so wrap in a promise here
|
|
26
|
+
return Promise.resolve().then(() => fn(resource))
|
|
27
|
+
.then((result) => runDisposer(resource, result))
|
|
28
|
+
.catch((err) => runDisposer(resource, err, true))
|
|
29
|
+
})
|
|
30
|
+
}
|
package/lib/util/fix-owner.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const util = require('util')
|
|
4
4
|
|
|
5
|
-
const chownr =
|
|
6
|
-
const mkdirp =
|
|
5
|
+
const chownr = util.promisify(require('chownr'))
|
|
6
|
+
const mkdirp = require('mkdirp')
|
|
7
7
|
const inflight = require('promise-inflight')
|
|
8
8
|
const inferOwner = require('infer-owner')
|
|
9
9
|
|
|
@@ -32,19 +32,20 @@ const getSelf = () => {
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
module.exports.chownr = fixOwner
|
|
35
|
+
|
|
35
36
|
function fixOwner (cache, filepath) {
|
|
36
37
|
if (!process.getuid) {
|
|
37
38
|
// This platform doesn't need ownership fixing
|
|
38
|
-
return
|
|
39
|
+
return Promise.resolve()
|
|
39
40
|
}
|
|
40
41
|
|
|
41
42
|
getSelf()
|
|
42
43
|
if (self.uid !== 0) {
|
|
43
44
|
// almost certainly can't chown anyway
|
|
44
|
-
return
|
|
45
|
+
return Promise.resolve()
|
|
45
46
|
}
|
|
46
47
|
|
|
47
|
-
return
|
|
48
|
+
return Promise.resolve(inferOwner(cache)).then((owner) => {
|
|
48
49
|
const { uid, gid } = owner
|
|
49
50
|
|
|
50
51
|
// No need to override if it's already what we used.
|
|
@@ -52,18 +53,23 @@ function fixOwner (cache, filepath) {
|
|
|
52
53
|
return
|
|
53
54
|
}
|
|
54
55
|
|
|
55
|
-
return inflight(
|
|
56
|
-
|
|
57
|
-
() => chownr(
|
|
56
|
+
return inflight('fixOwner: fixing ownership on ' + filepath, () =>
|
|
57
|
+
chownr(
|
|
58
58
|
filepath,
|
|
59
59
|
typeof uid === 'number' ? uid : self.uid,
|
|
60
60
|
typeof gid === 'number' ? gid : self.gid
|
|
61
|
-
).catch(
|
|
61
|
+
).catch((err) => {
|
|
62
|
+
if (err.code === 'ENOENT') {
|
|
63
|
+
return null
|
|
64
|
+
}
|
|
65
|
+
throw err
|
|
66
|
+
})
|
|
62
67
|
)
|
|
63
68
|
})
|
|
64
69
|
}
|
|
65
70
|
|
|
66
71
|
module.exports.chownr.sync = fixOwnerSync
|
|
72
|
+
|
|
67
73
|
function fixOwnerSync (cache, filepath) {
|
|
68
74
|
if (!process.getuid) {
|
|
69
75
|
// This platform doesn't need ownership fixing
|
|
@@ -71,6 +77,11 @@ function fixOwnerSync (cache, filepath) {
|
|
|
71
77
|
}
|
|
72
78
|
const { uid, gid } = inferOwner.sync(cache)
|
|
73
79
|
getSelf()
|
|
80
|
+
if (self.uid !== 0) {
|
|
81
|
+
// almost certainly can't chown anyway
|
|
82
|
+
return
|
|
83
|
+
}
|
|
84
|
+
|
|
74
85
|
if (self.uid === uid && self.gid === gid) {
|
|
75
86
|
// No need to override if it's already what we used.
|
|
76
87
|
return
|
|
@@ -91,24 +102,30 @@ function fixOwnerSync (cache, filepath) {
|
|
|
91
102
|
}
|
|
92
103
|
|
|
93
104
|
module.exports.mkdirfix = mkdirfix
|
|
105
|
+
|
|
94
106
|
function mkdirfix (cache, p, cb) {
|
|
95
107
|
// we have to infer the owner _before_ making the directory, even though
|
|
96
108
|
// we aren't going to use the results, since the cache itself might not
|
|
97
109
|
// exist yet. If we mkdirp it, then our current uid/gid will be assumed
|
|
98
110
|
// to be correct if it creates the cache folder in the process.
|
|
99
|
-
return
|
|
100
|
-
return mkdirp(p)
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
111
|
+
return Promise.resolve(inferOwner(cache)).then(() => {
|
|
112
|
+
return mkdirp(p)
|
|
113
|
+
.then((made) => {
|
|
114
|
+
if (made) {
|
|
115
|
+
return fixOwner(cache, made).then(() => made)
|
|
116
|
+
}
|
|
117
|
+
})
|
|
118
|
+
.catch((err) => {
|
|
119
|
+
if (err.code === 'EEXIST') {
|
|
120
|
+
return fixOwner(cache, p).then(() => null)
|
|
121
|
+
}
|
|
122
|
+
throw err
|
|
123
|
+
})
|
|
108
124
|
})
|
|
109
125
|
}
|
|
110
126
|
|
|
111
127
|
module.exports.mkdirfix.sync = mkdirfixSync
|
|
128
|
+
|
|
112
129
|
function mkdirfixSync (cache, p) {
|
|
113
130
|
try {
|
|
114
131
|
inferOwner.sync(cache)
|